tescmd 0.1.2__tar.gz → 0.2.0__tar.gz

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 (227) hide show
  1. tescmd-0.2.0/.github/workflows/publish.yml +19 -0
  2. tescmd-0.2.0/.github/workflows/test.yml +23 -0
  3. {tescmd-0.1.2 → tescmd-0.2.0}/CHANGELOG.md +31 -1
  4. {tescmd-0.1.2 → tescmd-0.2.0}/CLAUDE.md +36 -7
  5. {tescmd-0.1.2 → tescmd-0.2.0}/PKG-INFO +72 -35
  6. {tescmd-0.1.2 → tescmd-0.2.0}/README.md +68 -34
  7. {tescmd-0.1.2 → tescmd-0.2.0}/docs/architecture.md +27 -3
  8. {tescmd-0.1.2 → tescmd-0.2.0}/docs/bot-integration.md +38 -0
  9. {tescmd-0.1.2 → tescmd-0.2.0}/docs/commands.md +69 -3
  10. {tescmd-0.1.2 → tescmd-0.2.0}/docs/development.md +20 -22
  11. tescmd-0.2.0/docs/faq.md +108 -0
  12. tescmd-0.2.0/docs/setup.md +187 -0
  13. {tescmd-0.1.2 → tescmd-0.2.0}/pyproject.toml +13 -1
  14. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/__init__.py +1 -1
  15. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/client.py +8 -1
  16. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/errors.py +8 -0
  17. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/vehicle.py +19 -1
  18. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cache/response_cache.py +3 -2
  19. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/auth.py +30 -2
  20. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/key.py +149 -14
  21. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/main.py +44 -0
  22. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/setup.py +230 -22
  23. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/vehicle.py +464 -1
  24. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/crypto/__init__.py +3 -1
  25. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/crypto/ecdh.py +9 -0
  26. tescmd-0.2.0/src/tescmd/crypto/schnorr.py +191 -0
  27. tescmd-0.2.0/src/tescmd/deploy/tailscale_serve.py +154 -0
  28. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/__init__.py +0 -2
  29. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/auth.py +19 -0
  30. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/config.py +1 -0
  31. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/energy.py +0 -9
  32. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/session.py +10 -3
  33. tescmd-0.2.0/src/tescmd/telemetry/__init__.py +19 -0
  34. tescmd-0.2.0/src/tescmd/telemetry/dashboard.py +227 -0
  35. tescmd-0.2.0/src/tescmd/telemetry/decoder.py +284 -0
  36. tescmd-0.2.0/src/tescmd/telemetry/fields.py +248 -0
  37. tescmd-0.2.0/src/tescmd/telemetry/flatbuf.py +162 -0
  38. tescmd-0.2.0/src/tescmd/telemetry/protos/__init__.py +4 -0
  39. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_alert.proto +31 -0
  40. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_alert_pb2.py +42 -0
  41. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_alert_pb2.pyi +44 -0
  42. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_connectivity.proto +23 -0
  43. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_connectivity_pb2.py +40 -0
  44. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_connectivity_pb2.pyi +33 -0
  45. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_data.proto +768 -0
  46. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_data_pb2.py +136 -0
  47. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_data_pb2.pyi +1336 -0
  48. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_error.proto +23 -0
  49. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_error_pb2.py +44 -0
  50. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_error_pb2.pyi +39 -0
  51. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_metric.proto +22 -0
  52. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_metric_pb2.py +44 -0
  53. tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_metric_pb2.pyi +37 -0
  54. tescmd-0.2.0/src/tescmd/telemetry/server.py +293 -0
  55. tescmd-0.2.0/src/tescmd/telemetry/tailscale.py +300 -0
  56. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_cli_integration.py +1 -1
  57. tescmd-0.2.0/tests/cli/test_e2e_smoke.py +747 -0
  58. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_key.py +169 -5
  59. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_main_errors.py +7 -3
  60. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_setup.py +256 -0
  61. tescmd-0.2.0/tests/crypto/test_schnorr.py +245 -0
  62. tescmd-0.2.0/tests/deploy/test_tailscale_serve.py +270 -0
  63. tescmd-0.2.0/tests/telemetry/__init__.py +0 -0
  64. tescmd-0.2.0/tests/telemetry/conftest.py +34 -0
  65. tescmd-0.2.0/tests/telemetry/test_dashboard.py +220 -0
  66. tescmd-0.2.0/tests/telemetry/test_decoder.py +280 -0
  67. tescmd-0.2.0/tests/telemetry/test_fields.py +73 -0
  68. tescmd-0.2.0/tests/telemetry/test_flatbuf.py +179 -0
  69. tescmd-0.2.0/tests/telemetry/test_server.py +219 -0
  70. tescmd-0.2.0/tests/telemetry/test_stream_cmd.py +42 -0
  71. tescmd-0.2.0/tests/telemetry/test_tailscale.py +289 -0
  72. tescmd-0.1.2/.claude/settings.local.json +0 -47
  73. tescmd-0.1.2/docs/plans/2025-01-29-mvp-design.md +0 -152
  74. tescmd-0.1.2/docs/plans/2025-01-29-mvp-implementation.md +0 -3073
  75. tescmd-0.1.2/docs/setup-enrollment-audit.md +0 -171
  76. tescmd-0.1.2/scripts/e2e_test.py +0 -307
  77. {tescmd-0.1.2 → tescmd-0.2.0}/.gitignore +0 -0
  78. {tescmd-0.1.2 → tescmd-0.2.0}/LICENSE +0 -0
  79. {tescmd-0.1.2 → tescmd-0.2.0}/docs/api-costs.md +0 -0
  80. {tescmd-0.1.2 → tescmd-0.2.0}/docs/authentication.md +0 -0
  81. {tescmd-0.1.2 → tescmd-0.2.0}/docs/vehicle-command-protocol.md +0 -0
  82. {tescmd-0.1.2 → tescmd-0.2.0}/scripts/validate_fleet_api.py +0 -0
  83. {tescmd-0.1.2 → tescmd-0.2.0}/spec/fleet_api_spec.json +0 -0
  84. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/__main__.py +0 -0
  85. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/_internal/__init__.py +0 -0
  86. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/_internal/async_utils.py +0 -0
  87. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/_internal/permissions.py +0 -0
  88. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/_internal/vin.py +0 -0
  89. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/__init__.py +0 -0
  90. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/charging.py +0 -0
  91. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/command.py +0 -0
  92. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/energy.py +0 -0
  93. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/partner.py +0 -0
  94. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/sharing.py +0 -0
  95. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/signed_command.py +0 -0
  96. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/user.py +0 -0
  97. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/auth/__init__.py +0 -0
  98. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/auth/oauth.py +0 -0
  99. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/auth/server.py +0 -0
  100. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/auth/token_store.py +0 -0
  101. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/ble/__init__.py +0 -0
  102. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cache/__init__.py +0 -0
  103. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cache/keys.py +0 -0
  104. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/__init__.py +0 -0
  105. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/_client.py +0 -0
  106. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/_options.py +0 -0
  107. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/billing.py +0 -0
  108. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/cache.py +0 -0
  109. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/charge.py +0 -0
  110. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/climate.py +0 -0
  111. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/energy.py +0 -0
  112. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/media.py +0 -0
  113. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/nav.py +0 -0
  114. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/partner.py +0 -0
  115. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/raw.py +0 -0
  116. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/security.py +0 -0
  117. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/sharing.py +0 -0
  118. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/software.py +0 -0
  119. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/status.py +0 -0
  120. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/trunk.py +0 -0
  121. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/user.py +0 -0
  122. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/config/__init__.py +0 -0
  123. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/crypto/keys.py +0 -0
  124. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/deploy/__init__.py +0 -0
  125. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/deploy/github_pages.py +0 -0
  126. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/command.py +0 -0
  127. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/sharing.py +0 -0
  128. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/user.py +0 -0
  129. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/vehicle.py +0 -0
  130. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/output/__init__.py +0 -0
  131. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/output/formatter.py +0 -0
  132. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/output/json_output.py +0 -0
  133. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/output/rich_output.py +0 -0
  134. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/__init__.py +0 -0
  135. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/commands.py +0 -0
  136. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/encoder.py +0 -0
  137. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/metadata.py +0 -0
  138. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/payloads.py +0 -0
  139. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/protobuf/__init__.py +0 -0
  140. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/protobuf/messages.py +0 -0
  141. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/signer.py +0 -0
  142. {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/py.typed +0 -0
  143. {tescmd-0.1.2 → tescmd-0.2.0}/tests/__init__.py +0 -0
  144. {tescmd-0.1.2 → tescmd-0.2.0}/tests/_internal/__init__.py +0 -0
  145. {tescmd-0.1.2 → tescmd-0.2.0}/tests/_internal/test_async_utils.py +0 -0
  146. {tescmd-0.1.2 → tescmd-0.2.0}/tests/_internal/test_vin.py +0 -0
  147. {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/__init__.py +0 -0
  148. {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_client.py +0 -0
  149. {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_command_api.py +0 -0
  150. {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_energy_api.py +0 -0
  151. {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_partner_api.py +0 -0
  152. {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_sharing_api.py +0 -0
  153. {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_signed_command.py +0 -0
  154. {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_user_api.py +0 -0
  155. {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_vehicle_api.py +0 -0
  156. {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/__init__.py +0 -0
  157. {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_oauth.py +0 -0
  158. {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_oauth_extended.py +0 -0
  159. {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_server.py +0 -0
  160. {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_token_store.py +0 -0
  161. {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_token_store_fallback.py +0 -0
  162. {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_token_store_file.py +0 -0
  163. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cache/__init__.py +0 -0
  164. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cache/test_generic_cache.py +0 -0
  165. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cache/test_keys.py +0 -0
  166. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cache/test_response_cache.py +0 -0
  167. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/__init__.py +0 -0
  168. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/_helpers.py +0 -0
  169. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/conftest.py +0 -0
  170. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_auth.py +0 -0
  171. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_auth_exec.py +0 -0
  172. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_cache.py +0 -0
  173. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_cached_api_call.py +0 -0
  174. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_charge_exec.py +0 -0
  175. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_climate_exec.py +0 -0
  176. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_energy.py +0 -0
  177. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_energy_exec.py +0 -0
  178. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_error_handlers.py +0 -0
  179. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_key_enroll.py +0 -0
  180. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_key_unenroll.py +0 -0
  181. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_media.py +0 -0
  182. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_media_exec.py +0 -0
  183. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_nav.py +0 -0
  184. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_nav_exec.py +0 -0
  185. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_partner.py +0 -0
  186. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_raw.py +0 -0
  187. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_raw_exec.py +0 -0
  188. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_security_exec.py +0 -0
  189. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_setup_scope_check.py +0 -0
  190. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_sharing.py +0 -0
  191. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_sharing_exec.py +0 -0
  192. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_software.py +0 -0
  193. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_software_exec.py +0 -0
  194. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_status_exec.py +0 -0
  195. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_tier_enforcement.py +0 -0
  196. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_trunk_exec.py +0 -0
  197. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_user.py +0 -0
  198. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_user_exec.py +0 -0
  199. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_vcsec_guard.py +0 -0
  200. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_vehicle_exec.py +0 -0
  201. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_vehicle_power_exec.py +0 -0
  202. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_verbose.py +0 -0
  203. {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_wake_confirmation.py +0 -0
  204. {tescmd-0.1.2 → tescmd-0.2.0}/tests/conftest.py +0 -0
  205. {tescmd-0.1.2 → tescmd-0.2.0}/tests/crypto/__init__.py +0 -0
  206. {tescmd-0.1.2 → tescmd-0.2.0}/tests/crypto/test_ecdh.py +0 -0
  207. {tescmd-0.1.2 → tescmd-0.2.0}/tests/crypto/test_keys.py +0 -0
  208. {tescmd-0.1.2 → tescmd-0.2.0}/tests/deploy/__init__.py +0 -0
  209. {tescmd-0.1.2 → tescmd-0.2.0}/tests/deploy/test_github_pages.py +0 -0
  210. {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/__init__.py +0 -0
  211. {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_auth.py +0 -0
  212. {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_config.py +0 -0
  213. {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_energy.py +0 -0
  214. {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_sharing.py +0 -0
  215. {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_user_models.py +0 -0
  216. {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_vehicle.py +0 -0
  217. {tescmd-0.1.2 → tescmd-0.2.0}/tests/output/__init__.py +0 -0
  218. {tescmd-0.1.2 → tescmd-0.2.0}/tests/output/test_formatter.py +0 -0
  219. {tescmd-0.1.2 → tescmd-0.2.0}/tests/output/test_json_output.py +0 -0
  220. {tescmd-0.1.2 → tescmd-0.2.0}/tests/output/test_rich_output.py +0 -0
  221. {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/__init__.py +0 -0
  222. {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/conftest.py +0 -0
  223. {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/test_commands.py +0 -0
  224. {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/test_encoder.py +0 -0
  225. {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/test_metadata.py +0 -0
  226. {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/test_session.py +0 -0
  227. {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/test_signer.py +0 -0
@@ -0,0 +1,19 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ id-token: write # trusted publishing
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.12"
17
+ - run: pip install build
18
+ - run: python -m build
19
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,23 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.11", "3.12", "3.13"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - run: pip install -e ".[dev,telemetry]"
20
+ - run: ruff check src/ tests/
21
+ - run: ruff format --check src/ tests/
22
+ - run: mypy src/
23
+ - run: pytest
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.0] - 2026-01-31
9
+
10
+ ### Added
11
+
12
+ - **Fleet Telemetry Streaming** — `tescmd vehicle telemetry stream [VIN]` starts a local WebSocket server, exposes it via Tailscale Funnel, configures the vehicle to push real-time telemetry, and displays it in an interactive Rich Live dashboard (TTY) or JSONL stream (piped)
13
+ - **Telemetry dashboard** — Rich Live TUI with field name, value, and last-update columns; unit conversion (°F/°C, mi/km, psi/bar); connection status; frame counter; uptime display
14
+ - **Protobuf telemetry decoder** — official Tesla protobuf definitions (`vehicle_data`, `vehicle_alert`, `vehicle_error`, `vehicle_metric`, `vehicle_connectivity`) for fully typed telemetry message parsing
15
+ - **FlatBuffer telemetry support** — `flatbuf.py` parser for Tesla's FlatBuffer-encoded telemetry payloads alongside protobuf
16
+ - **Field presets** — `--fields` option accepts preset names (`default`, `driving`, `charging`, `climate`, `all`) or comma-separated field names with 120+ registered telemetry fields
17
+ - **Interval override** — `--interval` option overrides the polling interval for all fields
18
+ - **Tailscale Funnel integration** — automatic Funnel start/stop with cert retrieval for Fleet Telemetry HTTPS requirement
19
+ - **JSONL output** — piped mode emits one JSON line per telemetry frame for scripting and log ingestion
20
+ - **TunnelError hierarchy** — `TunnelError` parent with `TailscaleError` subtype; actionable install/setup guidance
21
+ - **Optional dependency group** — `pip install tescmd[telemetry]` adds `websockets>=14.0`
22
+ - **Tailscale key hosting** — `tescmd key deploy --method tailscale` hosts the public key via Tailscale Funnel at `https://<machine>.tailnet.ts.net/.well-known/appspecific/com.tesla.3p.public-key.pem`; auto-detected as second priority after GitHub Pages
23
+ - **Key hosting priority chain** — setup wizard and `key deploy` auto-detect the best hosting method: GitHub Pages → Tailscale Funnel → manual; `--method` flag overrides auto-detection
24
+ - **`TESLA_HOSTING_METHOD` setting** — persists the chosen key hosting method (`github`, `tailscale`) across sessions
25
+ - **Schnorr signature support** — `crypto/schnorr.py` for Schnorr-based authentication challenges used in telemetry server handshake
26
+ - **`auth import` command** — `tescmd auth import < tokens.json` imports tokens from a JSON file for headless/CI environments
27
+ - **Setup guide** — `docs/setup.md` with step-by-step walkthrough of all 7 setup phases
28
+ - **FAQ** — `docs/faq.md` covering common questions about tescmd, costs, hosting, and configuration
29
+ - **CI/CD workflows** — GitHub Actions for test-on-push (Python 3.11–3.13) and publish-to-PyPI-on-release via trusted publishing
30
+ - **README badges** — PyPI version, Python versions, CI build status, license, and GitHub release badges
31
+ - **E2E smoke tests** — `tests/cli/test_e2e_smoke.py` provides 179 pytest-based end-to-end tests covering every CLI command against the live Fleet API, with JSON envelope validation and save/restore for write commands (`pytest -m e2e`)
32
+
33
+ ### Fixed
34
+
35
+ - Fixed telemetry dashboard uptime counter not incrementing
36
+ - Improved tunnel start/stop success messages for clarity
37
+
8
38
  ## [0.1.2] - 2025-01-31
9
39
 
10
40
  ### Added
@@ -46,7 +76,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
46
76
  - **`command_protocol` setting** — `auto` (default), `signed`, or `unsigned` to control command routing; configurable via `TESLA_COMMAND_PROTOCOL` env var
47
77
  - **Enrollment step in setup wizard** — full-tier setup now offers to enroll the key on a vehicle after key generation
48
78
  - **Friendly command output** — all vehicle commands now display descriptive success messages (e.g. "Climate control turned on.", "Doors locked.") instead of bare "OK"
49
- - **E2E test script** — `scripts/e2e_test.py` provides interactive end-to-end command testing against a live vehicle with per-command confirmation, category filtering, and destructive-command skipping
79
+ - **E2E smoke tests** — `tests/cli/test_e2e_smoke.py` provides 179 pytest-based end-to-end tests covering every CLI command against the live Fleet API, with JSON envelope validation and save/restore for write commands (`pytest -m e2e`)
50
80
 
51
81
  ## [0.1.0]
52
82
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  **tescmd** is a Python CLI application that queries data from and sends commands to Tesla vehicles via the [Tesla Fleet API](https://developer.tesla.com/docs/fleet-api). The current implementation covers OAuth2 authentication, key management, vehicle state queries (battery, location, climate, drive state, tire pressure, trunks, and more), and both human-friendly (Rich TUI) and machine-friendly (JSON) output with configurable display units.
6
6
 
7
- **Current scope:** auth, vehicle queries, vehicle commands (charge, climate, security, trunk, media, nav, software), energy product management (including telemetry), Supercharger charging history and invoices, user account info, vehicle sharing, partner account endpoints (public key, fleet telemetry errors), key management with enrollment and unenrollment, Vehicle Command Protocol (ECDH sessions + HMAC-signed protobuf commands), tier enforcement, initial setup, response caching with cost-aware wake confirmation, Fleet Telemetry configuration management (create/delete/errors), configuration status dashboard, and GitHub Pages key deployment.
7
+ **Current scope:** auth, vehicle queries, vehicle commands (charge, climate, security, trunk, media, nav, software), energy product management (including telemetry), Supercharger charging history and invoices, user account info, vehicle sharing, partner account endpoints (public key, fleet telemetry errors), key management with enrollment and unenrollment, Vehicle Command Protocol (ECDH sessions + HMAC-signed protobuf commands), tier enforcement, initial setup, response caching with cost-aware wake confirmation, Fleet Telemetry configuration management (create/delete/errors), real-time telemetry streaming via Tailscale Funnel, configuration status dashboard, key deployment via GitHub Pages or Tailscale Funnel (auto-detected priority chain).
8
8
 
9
9
  ## Tech Stack
10
10
 
@@ -17,6 +17,7 @@
17
17
  - **protobuf** — protobuf serialization for Vehicle Command Protocol messages
18
18
  - **keyring** — OS-level credential storage for tokens
19
19
  - **python-dotenv** — `.env` file loading
20
+ - **websockets** — async WebSocket server for telemetry streaming (optional: `[telemetry]`)
20
21
  - **bleak** — BLE communication for key enrollment (optional; portal enrollment is primary)
21
22
 
22
23
  ## Project Structure
@@ -38,7 +39,7 @@ src/tescmd/
38
39
  │ ├── security.py # security status, lock, auto-secure, unlock, sentry, valet, valet-reset, remote-start, flash, honk, boombox, pin-to-drive, pin-reset, pin-clear-admin, speed-limit, speed-clear, speed-clear-admin, guest-mode, erase-data
39
40
  │ ├── status.py # status (show config, auth, and cache status)
40
41
  │ ├── trunk.py # trunk open, close, frunk, window, sunroof, tonneau-open/close/stop
41
- │ ├── vehicle.py # 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 subgroup: config, create, delete, errors
42
+ │ ├── vehicle.py # 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 subgroup: config, create, delete, errors, stream
42
43
  │ ├── media.py # media play-pause, next/prev track, next/prev fav, volume
43
44
  │ ├── nav.py # nav send, gps, supercharger, homelink, waypoints
44
45
  │ ├── partner.py # partner public-key, telemetry-error-vins, telemetry-errors
@@ -60,7 +61,7 @@ src/tescmd/
60
61
  │ ├── partner.py # PartnerAPI (public key, fleet telemetry errors — requires partner token)
61
62
  │ ├── sharing.py # SharingAPI (driver and invite management)
62
63
  │ ├── user.py # UserAPI (account info, region, orders, features)
63
- │ └── errors.py # API error types (incl. TierError, SessionError, KeyNotEnrolledError)
64
+ │ └── errors.py # API error types (incl. TierError, SessionError, KeyNotEnrolledError, TunnelError, TailscaleError)
64
65
  ├── cache/ # Response caching
65
66
  │ ├── __init__.py # Re-exports ResponseCache, generic_cache_key
66
67
  │ ├── response_cache.py # ResponseCache (file-based JSON with TTL, generic cache)
@@ -99,11 +100,19 @@ src/tescmd/
99
100
  │ ├── formatter.py # OutputFormatter (auto-detect TTY vs pipe)
100
101
  │ ├── rich_output.py # Rich tables, panels, status displays, DisplayUnits
101
102
  │ └── json_output.py # Structured JSON output
103
+ ├── telemetry/ # Fleet Telemetry streaming
104
+ │ ├── __init__.py # Re-exports
105
+ │ ├── tailscale.py # TailscaleManager: check presence, start/stop funnel, get cert, serve/funnel for key hosting
106
+ │ ├── server.py # TelemetryServer: async WebSocket server
107
+ │ ├── decoder.py # TelemetryDecoder: protobuf to TelemetryFrame dataclass
108
+ │ ├── fields.py # Field name registry (120+ fields) and preset configs
109
+ │ └── dashboard.py # TelemetryDashboard: Rich Live TUI renderer
102
110
  ├── ble/ # BLE communication (stub — enrollment not yet wired)
103
111
  │ └── __init__.py
104
112
  ├── deploy/ # Key deployment helpers
105
113
  │ ├── __init__.py
106
- └── github_pages.py # GitHub Pages deployment for public key hosting
114
+ ├── github_pages.py # GitHub Pages deployment for public key hosting
115
+ │ └── tailscale_serve.py # Tailscale Funnel deployment for public key hosting
107
116
  ├── config/ # Configuration (stub — settings in models/config.py)
108
117
  │ └── __init__.py
109
118
  └── _internal/ # Shared utilities
@@ -117,6 +126,15 @@ spec/
117
126
 
118
127
  scripts/
119
128
  └── validate_fleet_api.py # Spec-driven API coverage validator (AST-based)
129
+
130
+ tests/telemetry/
131
+ ├── conftest.py # Shared fixtures (cli_env)
132
+ ├── test_tailscale.py # Mocked subprocess tests for TailscaleManager
133
+ ├── test_decoder.py # Protobuf decode with crafted bytes
134
+ ├── test_fields.py # Field registry and preset resolution
135
+ ├── test_server.py # WebSocket client integration tests
136
+ ├── test_dashboard.py # Rich Live render output verification
137
+ └── test_stream_cmd.py # CLI integration tests for stream command
120
138
  ```
121
139
 
122
140
  ### Key Models (`models/vehicle.py`)
@@ -276,11 +294,12 @@ The `[R] Retry` option allows users to wake the vehicle for free via the Tesla m
276
294
 
277
295
  ## Testing
278
296
 
279
- - **pytest** + **pytest-asyncio** + **pytest-httpx**
297
+ - **pytest** + **pytest-asyncio** + **pytest-httpx** + **pytest-xdist**
298
+ - Tests run in parallel by default (`addopts = "-n auto"` in `pyproject.toml`). Always use `pytest` (not `pytest -n 1`) unless debugging a specific isolation issue.
280
299
  - Test files mirror source: `tests/cli/test_auth.py`, `tests/api/test_client.py`, etc.
281
300
  - Use `pytest-httpx` to mock HTTP responses (no live API calls in tests)
282
301
  - Async tests use `@pytest.mark.asyncio`
283
- - Current count: ~910 tests
302
+ - Current count: ~1118 tests
284
303
 
285
304
  ## Linting & Formatting
286
305
 
@@ -308,6 +327,8 @@ The `[R] Retry` option allows users to wake the vehicle for free via the Tesla m
308
327
  16. **Key enrollment** — `tescmd key enroll <VIN>` sends the public key to the vehicle via the unsigned `add_key_request` endpoint, then guides the user through Tesla app approval with an interactive prompt or `--wait` auto-polling.
309
328
  17. **Cross-platform token storage** — `TokenStore` uses a `_TokenBackend` protocol with two implementations: `_KeyringBackend` (OS keyring) and `_FileBackend` (JSON file with atomic writes and restricted permissions). Backend selection: explicit `TESLA_TOKEN_FILE` → file; keyring probe success → keyring; probe failure → file fallback at `{config_dir}/tokens.json` with one-time warning.
310
329
  18. **Cross-platform file permissions** — `_internal/permissions.py` provides `secure_file()` which uses `chmod 0600` on Unix and `icacls` on Windows. Used by both token storage and key generation. Failures are silently ignored (Docker volumes, network mounts, etc.).
330
+ 19. **Fleet Telemetry streaming** — `tescmd vehicle telemetry stream [VIN]` starts a local WebSocket server, exposes it via Tailscale Funnel, configures the vehicle's fleet telemetry config to push to it, and displays data in a Rich Live dashboard (TTY) or JSONL stream (piped). Tesla requires the telemetry config hostname to match the partner-registered domain — the stream command automatically re-registers the partner domain to match the tunnel hostname, then restores the original domain on exit (try/finally). The `telemetry/` package has five modules: `TailscaleManager` (subprocess-based — Funnel has no Python API), `TelemetryServer` (websockets async server), `TelemetryDecoder` (reuses `protocol/protobuf/messages._decode_field` for wire-format parsing), `fields.py` (120+ field name registry with presets), and `TelemetryDashboard` (Rich Live TUI with unit conversion via `DisplayUnits`). Port is randomly selected from ephemeral range (49152–65535). Cleanup is guaranteed via try/finally (partner domain restore → telemetry config delete → funnel stop → server stop). Optional dependency: `pip install tescmd[telemetry]` adds `websockets>=14.0`.
331
+ 20. **Key hosting priority chain** — `tescmd setup` and `tescmd key deploy` auto-detect the best hosting method for the public key: GitHub Pages (always-on, free) → Tailscale Funnel (requires machine running) → manual. The `--method` flag on `key deploy` overrides auto-detection. `TESLA_HOSTING_METHOD` persists the choice. Tailscale key hosting uses path-based `tailscale serve --bg --set-path /.well-known/ <dir>` + `tailscale funnel --bg 443`. Note: Tailscale key hosting may conflict with telemetry streaming's funnel usage — run `tescmd key deploy --method tailscale` to re-enable after streaming.
311
332
 
312
333
  ## Environment Variables
313
334
 
@@ -333,6 +354,7 @@ The `[R] Retry` option allows users to wake the vehicle for free via the Tesla m
333
354
  | `TESLA_DOMAIN` | Domain for Fleet API key hosting | — |
334
355
  | `TESLA_SETUP_TIER` | Setup tier (`readonly` or `full`) | — |
335
356
  | `TESLA_GITHUB_REPO` | GitHub repo for key deployment (e.g., `user/user.github.io`) | — |
357
+ | `TESLA_HOSTING_METHOD` | Key hosting method (`github`, `tailscale`, or unset for manual) | — |
336
358
 
337
359
  All variables can also be set in a `.env` file in the working directory or `$TESLA_CONFIG_DIR/.env`.
338
360
 
@@ -349,7 +371,6 @@ All variables can also be set in a `.env` file in the working directory or `$TES
349
371
  | `--no-cache` / `--fresh` | Global | Bypass response cache for this invocation |
350
372
  | `--wake` | Global | Auto-wake vehicle without confirmation (billable) |
351
373
  | `--units {us,metric}` | Global | Display units preset (us: °F/mi/psi, metric: °C/km/bar) |
352
-
353
374
  All global flags can be specified at the root level (`tescmd --wake charge status`) or after the subcommand (`tescmd charge status --wake`).
354
375
 
355
376
  ## API Coverage Validation
@@ -398,4 +419,12 @@ tescmd cache clear --scope account # Clear account-level entries
398
419
  tescmd charge status # Uses cache, prompts before wake
399
420
  tescmd charge status --fresh # Bypasses cache, still prompts before wake
400
421
  tescmd charge status --wake # Auto-wakes without prompting (billable)
422
+
423
+ # Telemetry streaming (requires: pip install tescmd[telemetry] + Tailscale)
424
+ tescmd vehicle telemetry stream VIN # Rich Live dashboard
425
+ tescmd vehicle telemetry stream VIN --fields driving # Driving preset
426
+ tescmd vehicle telemetry stream VIN --fields charging # Charging preset
427
+ tescmd vehicle telemetry stream VIN --interval 5 # Override all field intervals to 5s
428
+ tescmd vehicle telemetry stream VIN --format json # JSONL output for scripting
429
+ pytest tests/telemetry/ # Telemetry-specific tests
401
430
  ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tescmd
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: A Python CLI for querying and controlling Tesla vehicles via the Fleet API
5
5
  Project-URL: Homepage, https://github.com/oceanswave/tescmd
6
6
  Project-URL: Repository, https://github.com/oceanswave/tescmd
@@ -41,15 +41,20 @@ Requires-Dist: mypy>=1.13; extra == 'dev'
41
41
  Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
42
42
  Requires-Dist: pytest-cov>=5.0; extra == 'dev'
43
43
  Requires-Dist: pytest-httpx>=0.34; extra == 'dev'
44
+ Requires-Dist: pytest-xdist>=3.0; extra == 'dev'
44
45
  Requires-Dist: pytest>=8.0; extra == 'dev'
45
46
  Requires-Dist: ruff>=0.8; extra == 'dev'
47
+ Provides-Extra: telemetry
48
+ Requires-Dist: websockets>=14.0; extra == 'telemetry'
46
49
  Description-Content-Type: text/markdown
47
50
 
48
51
  # tescmd
49
52
 
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/) -->
53
+ [![PyPI](https://img.shields.io/pypi/v/tescmd)](https://pypi.org/project/tescmd/)
54
+ [![Python](https://img.shields.io/pypi/pyversions/tescmd)](https://pypi.org/project/tescmd/)
55
+ [![Build](https://img.shields.io/github/actions/workflow/status/oceanswave/tescmd/test.yml?branch=main&label=build)](https://github.com/oceanswave/tescmd/actions/workflows/test.yml)
52
56
  [![License](https://img.shields.io/github/license/oceanswave/tescmd)](LICENSE)
57
+ [![GitHub Release](https://img.shields.io/github/v/release/oceanswave/tescmd)](https://github.com/oceanswave/tescmd/releases)
53
58
 
54
59
  A Python CLI for querying and controlling Tesla vehicles via the Fleet API — built for both human operators and AI agents.
55
60
 
@@ -68,7 +73,7 @@ tescmd is designed to work as a tool that AI agents can invoke directly. Platfor
68
73
  - **Tier enforcement** — readonly tier blocks write commands with clear guidance to upgrade
69
74
  - **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
75
  - **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
76
+ - **Fleet Telemetry streaming** — `tescmd vehicle telemetry stream` starts a real-time dashboard with push-based data from your vehicle via Tailscale Funnel — no polling, 99%+ cost reduction
72
77
  - **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
78
  - **Cost-aware wake** — prompts before sending billable wake API calls; `--wake` flag for scripts that accept the cost
74
79
  - **Guided OAuth2 setup** — `tescmd auth login` walks you through browser-based authentication with PKCE
@@ -83,40 +88,23 @@ tescmd is designed to work as a tool that AI agents can invoke directly. Platfor
83
88
 
84
89
  ```bash
85
90
  pip install tescmd
86
-
87
- # First-time setup (interactive wizard)
88
91
  tescmd setup
92
+ ```
89
93
 
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
94
+ That's it. The interactive setup wizard walks you through everything: creating a Tesla Developer app, generating an EC key pair, hosting the public key (via GitHub Pages or Tailscale Funnel), registering with the Fleet API, authenticating via OAuth2, and enrolling your key on a vehicle. Each step checks prerequisites and offers remediation if something is missing.
111
95
 
112
- # Enroll your key on a vehicle (required for signed commands)
113
- tescmd key enroll 5YJ3E1EA1NF000000
96
+ After setup completes, you can start using commands:
114
97
 
115
- # Cache management
116
- tescmd cache status
117
- tescmd cache clear
98
+ ```bash
99
+ tescmd charge status # Check battery and charging state
100
+ tescmd vehicle info # Full vehicle data snapshot
101
+ tescmd climate on --wake # Turn on climate (wakes vehicle if asleep)
102
+ tescmd security lock --wake # Lock the car
103
+ tescmd vehicle telemetry stream # Real-time telemetry dashboard
118
104
  ```
119
105
 
106
+ Every read command is cached — repeat calls within the TTL window are instant and free.
107
+
120
108
  ## Prerequisites
121
109
 
122
110
  The following tools should be installed and authenticated before running `tescmd setup`:
@@ -125,9 +113,11 @@ The following tools should be installed and authenticated before running `tescmd
125
113
  |------|----------|---------|------|
126
114
  | **Git** | Yes | Version control, repo management | N/A |
127
115
  | **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` |
116
+ | **Tailscale** | Optional | Key hosting via Funnel + Fleet Telemetry streaming | `tailscale login` |
117
+
118
+ Without the GitHub CLI, `tescmd setup` will try Tailscale Funnel for key hosting (requires Funnel enabled in your tailnet ACL). Without either, you'll need to manually host your public key at the Tesla-required `.well-known` path on your own domain.
129
119
 
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.
120
+ For telemetry streaming, you need **Tailscale** with Funnel enabled.
131
121
 
132
122
  ## Installation
133
123
 
@@ -210,7 +200,7 @@ Check which backend is active with `tescmd status` — the output includes a `To
210
200
  |---|---|---|
211
201
  | `setup` | *(interactive wizard)* | First-run configuration: client ID, secret, region, domain, key enrollment |
212
202
  | `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 |
203
+ | `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,stream}` | Vehicle discovery, state queries, fleet telemetry streaming, power management |
214
204
  | `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
205
  | `billing` | `history`, `sessions`, `invoice` | Supercharger billing history and invoices |
216
206
  | `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 |
@@ -355,6 +345,41 @@ Configure via environment variables:
355
345
  | `TESLA_CACHE_TTL` | `60` | Time-to-live in seconds |
356
346
  | `TESLA_CACHE_DIR` | `~/.cache/tescmd` | Cache directory path |
357
347
 
348
+ ## Fleet Telemetry Streaming
349
+
350
+ Tesla's Fleet Telemetry lets your vehicle push real-time data directly to your server — no polling, no per-request charges. tescmd handles all the setup:
351
+
352
+ ```bash
353
+ # Install telemetry dependencies
354
+ pip install tescmd[telemetry]
355
+
356
+ # Stream real-time data (Rich dashboard in TTY, JSONL when piped)
357
+ tescmd vehicle telemetry stream
358
+
359
+ # Select field presets
360
+ tescmd vehicle telemetry stream --fields driving # Speed, location, power
361
+ tescmd vehicle telemetry stream --fields charging # Battery, voltage, current
362
+ tescmd vehicle telemetry stream --fields climate # Temps, HVAC state
363
+ tescmd vehicle telemetry stream --fields all # Everything (120+ fields)
364
+
365
+ # Override polling interval
366
+ tescmd vehicle telemetry stream --interval 5 # Every 5 seconds
367
+
368
+ # JSONL output for scripting
369
+ tescmd vehicle telemetry stream --format json | jq .
370
+ ```
371
+
372
+ **Requires Tailscale** with Funnel enabled. The stream command starts a local WebSocket server, exposes it via Tailscale Funnel (handles TLS + NAT traversal), configures Tesla to push data to it, and renders an interactive dashboard with live uptime counter, unit conversion, and connection status. Press `q` to stop — cleanup messages show each step (removing telemetry config, restoring partner domain, stopping tunnel).
373
+
374
+ ### Telemetry vs Polling Costs
375
+
376
+ | Approach | 1 vehicle, 5-second interval, 24 hours | Monthly cost estimate |
377
+ |---|---|---|
378
+ | **Polling `vehicle_data`** | ~17,280 requests × $0.001 = **$17/day** | **$500+/month** |
379
+ | **Fleet Telemetry streaming** | 1 config create + 1 config delete = **2 requests** | **< $0.01/month** |
380
+
381
+ Fleet Telemetry streaming is a flat-cost alternative: you pay only for the initial config setup and teardown, regardless of how much data flows. The tradeoff is that you need Tailscale running on a machine to receive the push.
382
+
358
383
  ## Key Enrollment & Vehicle Command Protocol
359
384
 
360
385
  Newer Tesla vehicles require commands to be signed using the [Vehicle Command Protocol](https://github.com/teslamotors/vehicle-command). tescmd handles this transparently:
@@ -449,6 +474,18 @@ Run this periodically or after modifying API methods to catch drift.
449
474
 
450
475
  See [docs/development.md](docs/development.md) for detailed contribution guidelines.
451
476
 
477
+ ## Documentation
478
+
479
+ - [Setup Guide](docs/setup.md) — step-by-step walkthrough of `tescmd setup`
480
+ - [FAQ](docs/faq.md) — common questions about tescmd, costs, hosting, and configuration
481
+ - [Command Reference](docs/commands.md) — detailed usage for every command
482
+ - [API Costs](docs/api-costs.md) — detailed cost breakdown and savings calculations
483
+ - [Bot Integration](docs/bot-integration.md) — JSON schema, exit codes, telemetry streaming, headless auth
484
+ - [Architecture](docs/architecture.md) — layered design, module responsibilities, design decisions
485
+ - [Vehicle Command Protocol](docs/vehicle-command-protocol.md) — ECDH sessions and signed commands
486
+ - [Authentication](docs/authentication.md) — OAuth2 PKCE flow, token storage, scopes
487
+ - [Development](docs/development.md) — contribution guidelines, testing, linting
488
+
452
489
  ## Changelog
453
490
 
454
491
  See [CHANGELOG.md](CHANGELOG.md) for release history.
@@ -1,8 +1,10 @@
1
1
  # tescmd
2
2
 
3
- <!-- [![PyPI](https://img.shields.io/pypi/v/tescmd)](https://pypi.org/project/tescmd/) -->
4
- <!-- [![Python](https://img.shields.io/pypi/pyversions/tescmd)](https://pypi.org/project/tescmd/) -->
3
+ [![PyPI](https://img.shields.io/pypi/v/tescmd)](https://pypi.org/project/tescmd/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/tescmd)](https://pypi.org/project/tescmd/)
5
+ [![Build](https://img.shields.io/github/actions/workflow/status/oceanswave/tescmd/test.yml?branch=main&label=build)](https://github.com/oceanswave/tescmd/actions/workflows/test.yml)
5
6
  [![License](https://img.shields.io/github/license/oceanswave/tescmd)](LICENSE)
7
+ [![GitHub Release](https://img.shields.io/github/v/release/oceanswave/tescmd)](https://github.com/oceanswave/tescmd/releases)
6
8
 
7
9
  A Python CLI for querying and controlling Tesla vehicles via the Fleet API — built for both human operators and AI agents.
8
10
 
@@ -21,7 +23,7 @@ tescmd is designed to work as a tool that AI agents can invoke directly. Platfor
21
23
  - **Tier enforcement** — readonly tier blocks write commands with clear guidance to upgrade
22
24
  - **Energy products** — Powerwall live status, site info, backup reserve, operation mode, storm mode, time-of-use settings, charging history, calendar history, grid import/export
23
25
  - **User & sharing** — account info, region, orders, feature flags, driver management, vehicle sharing invites
24
- - **Fleet Telemetry awareness** — setup wizard highlights Fleet Telemetry streaming for up to 97% API cost reduction
26
+ - **Fleet Telemetry streaming** — `tescmd vehicle telemetry stream` starts a real-time dashboard with push-based data from your vehicle via Tailscale Funnel — no polling, 99%+ cost reduction
25
27
  - **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
26
28
  - **Cost-aware wake** — prompts before sending billable wake API calls; `--wake` flag for scripts that accept the cost
27
29
  - **Guided OAuth2 setup** — `tescmd auth login` walks you through browser-based authentication with PKCE
@@ -36,40 +38,23 @@ tescmd is designed to work as a tool that AI agents can invoke directly. Platfor
36
38
 
37
39
  ```bash
38
40
  pip install tescmd
39
-
40
- # First-time setup (interactive wizard)
41
41
  tescmd setup
42
+ ```
42
43
 
43
- # Authenticate (opens browser)
44
- tescmd auth login
45
-
46
- # List your vehicles
47
- tescmd vehicle list
48
-
49
- # Get full vehicle data snapshot
50
- tescmd vehicle info
51
-
52
- # Check charge status (uses cache — second call is instant)
53
- tescmd charge status
54
-
55
- # Start charging (auto-invalidates cache)
56
- tescmd charge start --wake
57
-
58
- # Climate control
59
- tescmd climate on --wake
60
- tescmd climate set 72
61
-
62
- # Lock the car
63
- tescmd security lock --wake
44
+ That's it. The interactive setup wizard walks you through everything: creating a Tesla Developer app, generating an EC key pair, hosting the public key (via GitHub Pages or Tailscale Funnel), registering with the Fleet API, authenticating via OAuth2, and enrolling your key on a vehicle. Each step checks prerequisites and offers remediation if something is missing.
64
45
 
65
- # Enroll your key on a vehicle (required for signed commands)
66
- tescmd key enroll 5YJ3E1EA1NF000000
46
+ After setup completes, you can start using commands:
67
47
 
68
- # Cache management
69
- tescmd cache status
70
- tescmd cache clear
48
+ ```bash
49
+ tescmd charge status # Check battery and charging state
50
+ tescmd vehicle info # Full vehicle data snapshot
51
+ tescmd climate on --wake # Turn on climate (wakes vehicle if asleep)
52
+ tescmd security lock --wake # Lock the car
53
+ tescmd vehicle telemetry stream # Real-time telemetry dashboard
71
54
  ```
72
55
 
56
+ Every read command is cached — repeat calls within the TTL window are instant and free.
57
+
73
58
  ## Prerequisites
74
59
 
75
60
  The following tools should be installed and authenticated before running `tescmd setup`:
@@ -78,9 +63,11 @@ The following tools should be installed and authenticated before running `tescmd
78
63
  |------|----------|---------|------|
79
64
  | **Git** | Yes | Version control, repo management | N/A |
80
65
  | **GitHub CLI** (`gh`) | Recommended | Auto-creates `*.github.io` domain for key hosting | `gh auth login` |
81
- | **Tailscale** | Optional | Secure remote access to vehicles via Fleet Telemetry | `tailscale login` |
66
+ | **Tailscale** | Optional | Key hosting via Funnel + Fleet Telemetry streaming | `tailscale login` |
67
+
68
+ Without the GitHub CLI, `tescmd setup` will try Tailscale Funnel for key hosting (requires Funnel enabled in your tailnet ACL). Without either, you'll need to manually host your public key at the Tesla-required `.well-known` path on your own domain.
82
69
 
83
- 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.
70
+ For telemetry streaming, you need **Tailscale** with Funnel enabled.
84
71
 
85
72
  ## Installation
86
73
 
@@ -163,7 +150,7 @@ Check which backend is active with `tescmd status` — the output includes a `To
163
150
  |---|---|---|
164
151
  | `setup` | *(interactive wizard)* | First-run configuration: client ID, secret, region, domain, key enrollment |
165
152
  | `auth` | `login`, `logout`, `status`, `refresh`, `register`, `export`, `import` | OAuth2 authentication lifecycle |
166
- | `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 |
153
+ | `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,stream}` | Vehicle discovery, state queries, fleet telemetry streaming, power management |
167
154
  | `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 |
168
155
  | `billing` | `history`, `sessions`, `invoice` | Supercharger billing history and invoices |
169
156
  | `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 |
@@ -308,6 +295,41 @@ Configure via environment variables:
308
295
  | `TESLA_CACHE_TTL` | `60` | Time-to-live in seconds |
309
296
  | `TESLA_CACHE_DIR` | `~/.cache/tescmd` | Cache directory path |
310
297
 
298
+ ## Fleet Telemetry Streaming
299
+
300
+ Tesla's Fleet Telemetry lets your vehicle push real-time data directly to your server — no polling, no per-request charges. tescmd handles all the setup:
301
+
302
+ ```bash
303
+ # Install telemetry dependencies
304
+ pip install tescmd[telemetry]
305
+
306
+ # Stream real-time data (Rich dashboard in TTY, JSONL when piped)
307
+ tescmd vehicle telemetry stream
308
+
309
+ # Select field presets
310
+ tescmd vehicle telemetry stream --fields driving # Speed, location, power
311
+ tescmd vehicle telemetry stream --fields charging # Battery, voltage, current
312
+ tescmd vehicle telemetry stream --fields climate # Temps, HVAC state
313
+ tescmd vehicle telemetry stream --fields all # Everything (120+ fields)
314
+
315
+ # Override polling interval
316
+ tescmd vehicle telemetry stream --interval 5 # Every 5 seconds
317
+
318
+ # JSONL output for scripting
319
+ tescmd vehicle telemetry stream --format json | jq .
320
+ ```
321
+
322
+ **Requires Tailscale** with Funnel enabled. The stream command starts a local WebSocket server, exposes it via Tailscale Funnel (handles TLS + NAT traversal), configures Tesla to push data to it, and renders an interactive dashboard with live uptime counter, unit conversion, and connection status. Press `q` to stop — cleanup messages show each step (removing telemetry config, restoring partner domain, stopping tunnel).
323
+
324
+ ### Telemetry vs Polling Costs
325
+
326
+ | Approach | 1 vehicle, 5-second interval, 24 hours | Monthly cost estimate |
327
+ |---|---|---|
328
+ | **Polling `vehicle_data`** | ~17,280 requests × $0.001 = **$17/day** | **$500+/month** |
329
+ | **Fleet Telemetry streaming** | 1 config create + 1 config delete = **2 requests** | **< $0.01/month** |
330
+
331
+ Fleet Telemetry streaming is a flat-cost alternative: you pay only for the initial config setup and teardown, regardless of how much data flows. The tradeoff is that you need Tailscale running on a machine to receive the push.
332
+
311
333
  ## Key Enrollment & Vehicle Command Protocol
312
334
 
313
335
  Newer Tesla vehicles require commands to be signed using the [Vehicle Command Protocol](https://github.com/teslamotors/vehicle-command). tescmd handles this transparently:
@@ -402,6 +424,18 @@ Run this periodically or after modifying API methods to catch drift.
402
424
 
403
425
  See [docs/development.md](docs/development.md) for detailed contribution guidelines.
404
426
 
427
+ ## Documentation
428
+
429
+ - [Setup Guide](docs/setup.md) — step-by-step walkthrough of `tescmd setup`
430
+ - [FAQ](docs/faq.md) — common questions about tescmd, costs, hosting, and configuration
431
+ - [Command Reference](docs/commands.md) — detailed usage for every command
432
+ - [API Costs](docs/api-costs.md) — detailed cost breakdown and savings calculations
433
+ - [Bot Integration](docs/bot-integration.md) — JSON schema, exit codes, telemetry streaming, headless auth
434
+ - [Architecture](docs/architecture.md) — layered design, module responsibilities, design decisions
435
+ - [Vehicle Command Protocol](docs/vehicle-command-protocol.md) — ECDH sessions and signed commands
436
+ - [Authentication](docs/authentication.md) — OAuth2 PKCE flow, token storage, scopes
437
+ - [Development](docs/development.md) — contribution guidelines, testing, linting
438
+
405
439
  ## Changelog
406
440
 
407
441
  See [CHANGELOG.md](CHANGELOG.md) for release history.
@@ -31,9 +31,15 @@ tescmd follows a layered architecture with strict separation of concerns. Each l
31
31
  │ auth/oauth.py ─ auth/token_store.py │
32
32
  │ (OAuth2 PKCE, token refresh, keyring) │
33
33
  ├─────────────────────────────────────────────────┤
34
+ │ Telemetry Layer │
35
+ │ telemetry/server.py ─ telemetry/decoder.py │
36
+ │ telemetry/dashboard.py ─ telemetry/fields.py │
37
+ │ telemetry/tailscale.py ─ telemetry/flatbuf.py │
38
+ │ (WebSocket server, protobuf decode, Rich TUI) │
39
+ ├─────────────────────────────────────────────────┤
34
40
  │ Infrastructure │
35
41
  │ output/ ─ crypto/ ─ models/ ─ _internal/ │
36
- │ cache/ ─ (formatting, keys, schemas, helpers)
42
+ │ cache/ ─ deploy/ ─ (formatting, keys, schemas)
37
43
  └─────────────────────────────────────────────────┘
38
44
  ```
39
45
 
@@ -115,7 +121,7 @@ CLI modules do **not** construct HTTP requests or handle auth tokens directly.
115
121
 
116
122
  **Currently implemented command groups:**
117
123
  - `auth` — login (`--reconsent`), logout, status, refresh, register, export, import
118
- - `vehicle` — list, info, data, location, wake, alerts, release-notes, service, drivers
124
+ - `vehicle` — list, info, data, location, wake, alerts, release-notes, service, drivers, telemetry (config, create, delete, errors, stream)
119
125
  - `charge` — status, start, stop, limit, amps, schedule, departure, precondition
120
126
  - `climate` — status, on, off, set, seat, keeper, cop-temp, auto-seat, auto-wheel, wheel-level
121
127
  - `security` — status, lock, unlock, sentry, valet, remote-start, flash, honk, speed-limit, pin management
@@ -140,7 +146,7 @@ CLI modules do **not** construct HTTP requests or handle auth tokens directly.
140
146
  - **`energy.py`** (`EnergyAPI`) — Energy product endpoints (Powerwall, solar).
141
147
  - **`sharing.py`** (`SharingAPI`) — Driver and invite management.
142
148
  - **`user.py`** (`UserAPI`) — Account info, region, orders, features.
143
- - **`errors.py`** — Typed exceptions: `AuthError`, `MissingScopesError`, `VehicleAsleepError`, `SessionError`, `KeyNotEnrolledError`, `TierError`, `RateLimitError`, etc.
149
+ - **`errors.py`** — Typed exceptions: `AuthError`, `MissingScopesError`, `VehicleAsleepError`, `SessionError`, `KeyNotEnrolledError`, `TierError`, `RateLimitError`, `TunnelError`, `TailscaleError`, etc.
144
150
 
145
151
  API classes use **composition**: they receive a `TeslaFleetClient` instance, not extend it.
146
152
 
@@ -188,6 +194,7 @@ See [vehicle-command-protocol.md](vehicle-command-protocol.md) for the full prot
188
194
 
189
195
  - **`keys.py`** — EC P-256 key generation, PEM export/import, public key extraction.
190
196
  - **`ecdh.py`** — ECDH key exchange (`derive_session_key`) and uncompressed public key extraction.
197
+ - **`schnorr.py`** — Schnorr signature implementation for telemetry server authentication handshake.
191
198
 
192
199
  ### `output/` — Output Formatting
193
200
 
@@ -195,10 +202,27 @@ See [vehicle-command-protocol.md](vehicle-command-protocol.md) for the full prot
195
202
  - **`rich_output.py`** — Rich-based rendering: tables for vehicle data, charge status, climate status, vehicle config, GUI settings. Includes `DisplayUnits` for configurable unit conversion (°F/°C, mi/km, PSI/bar).
196
203
  - **`json_output.py`** — JSON serialization with consistent structure for machine parsing.
197
204
 
205
+ ### `telemetry/` — Fleet Telemetry Streaming
206
+
207
+ - **`server.py`** (`TelemetryServer`) — Async WebSocket server that receives telemetry push from Tesla. Handles TLS via Tailscale Funnel certs, Schnorr-based authentication handshake, and frame dispatch.
208
+ - **`decoder.py`** (`TelemetryDecoder`) — Decodes protobuf-encoded telemetry payloads using official Tesla proto definitions (`vehicle_data`, `vehicle_alert`, `vehicle_error`, `vehicle_metric`, `vehicle_connectivity`). Returns typed `TelemetryFrame` dataclasses.
209
+ - **`flatbuf.py`** — FlatBuffer parser for Tesla's alternative telemetry encoding format.
210
+ - **`fields.py`** — Field name registry (120+ fields) with preset configs (`default`, `driving`, `charging`, `climate`, `all`). Maps field names to protobuf field numbers.
211
+ - **`dashboard.py`** (`TelemetryDashboard`) — Rich Live TUI with field name, value, and last-update columns. Supports unit conversion via `DisplayUnits`, connection status, frame counter, and uptime display.
212
+ - **`tailscale.py`** (`TailscaleManager`) — Subprocess-based Tailscale management: check installation, start/stop Funnel, retrieve TLS certs, serve files at specific paths.
213
+
214
+ **Optional dependency:** `pip install tescmd[telemetry]` adds `websockets>=14.0`.
215
+
216
+ ### `deploy/` — Key Deployment
217
+
218
+ - **`github_pages.py`** — Deploys the public key to a GitHub Pages repo at the `.well-known` path.
219
+ - **`tailscale_serve.py`** — Hosts the public key via Tailscale Funnel at `https://<machine>.tailnet.ts.net/.well-known/appspecific/com.tesla.3p.public-key.pem`.
220
+
198
221
  ### `_internal/` — Shared Utilities
199
222
 
200
223
  - **`vin.py`** — Smart VIN resolution: checks positional arg, `--vin` flag, active profile, then falls back to interactive vehicle picker.
201
224
  - **`async_utils.py`** — `run_async()` helper for running async code from sync Click entry points.
225
+ - **`permissions.py`** — Cross-platform file permissions: `secure_file()` uses `chmod 0600` on Unix and `icacls` on Windows.
202
226
 
203
227
  ## Design Decisions
204
228