tesla-cli 4.8.1__tar.gz → 4.9.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.

Potentially problematic release.


This version of tesla-cli might be problematic. Click here for more details.

Files changed (326) hide show
  1. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/CHANGELOG.md +38 -0
  2. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/CLAUDE.md +1 -1
  3. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/PKG-INFO +1 -5
  4. tesla_cli-4.9.0/cron-runt-check.sh +39 -0
  5. tesla_cli-4.9.0/plugins/claude-code/skills/energy/SKILL.md +74 -0
  6. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/order/SKILL.md +2 -2
  7. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/pyproject.toml +1 -2
  8. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/__init__.py +1 -1
  9. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/app.py +150 -110
  10. tesla_cli-4.9.0/src/tesla_cli/api/routes/abrp.py +73 -0
  11. tesla_cli-4.9.0/src/tesla_cli/api/routes/automations.py +131 -0
  12. tesla_cli-4.9.0/src/tesla_cli/api/routes/ble.py +114 -0
  13. tesla_cli-4.9.0/src/tesla_cli/api/routes/charge.py +360 -0
  14. tesla_cli-4.9.0/src/tesla_cli/api/routes/dashcam.py +102 -0
  15. tesla_cli-4.9.0/src/tesla_cli/api/routes/energy_mgmt.py +119 -0
  16. tesla_cli-4.9.0/src/tesla_cli/api/routes/energy_prices.py +108 -0
  17. tesla_cli-4.9.0/src/tesla_cli/api/routes/mqtt.py +85 -0
  18. tesla_cli-4.9.0/src/tesla_cli/api/routes/notify.py +193 -0
  19. tesla_cli-4.9.0/src/tesla_cli/api/routes/order.py +50 -0
  20. tesla_cli-4.9.0/src/tesla_cli/api/routes/scenes.py +218 -0
  21. tesla_cli-4.9.0/src/tesla_cli/api/routes/service.py +127 -0
  22. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/vehicle.py +7 -0
  23. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Action-Bx3ITOrA.js +1 -0
  24. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Action-legacy-3WvXcEZ2.js +1 -0
  25. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Analytics-buNYOtEj.js +1 -0
  26. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Analytics-legacy-BuePPNnL.js +1 -0
  27. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Automations-4tvMUHNd.js +1 -0
  28. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Automations-legacy-CQbByZ9U.js +1 -0
  29. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/BarChart-C0vhuT9k.js +32 -0
  30. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/BarChart-legacy-D6VWK1UH.js +10 -0
  31. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/ChargeContent-iS7RMYje.js +1 -0
  32. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/ChargeContent-legacy-B-HEhFFx.js +1 -0
  33. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/ClimateContent-legacy-vnEmaAAb.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/ClimateContent-legacy-BQrDkZQd.js +1 -1
  34. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/ClimateContent-nHWdn2-B.js +1 -0
  35. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/ControlsContent-BBBfJYQI.js +1 -0
  36. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/ControlsContent-legacy-DtgtKrEG.js +1 -0
  37. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Dossier-CdecB5e7.js +1 -0
  38. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Dossier-legacy-FePjUmKv.js +1 -0
  39. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Energy-C6k2P_bp.js +1 -0
  40. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Energy-legacy-WmNeX_MR.js +1 -0
  41. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Icons-BPrRnLWP.js +1 -0
  42. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Icons-legacy-CacO0o_R.js +1 -0
  43. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Navigation-CuZJEwUU.js +1 -0
  44. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Navigation-legacy-DoiCAHN8.js +1 -0
  45. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Order-legacy-BIct8DQc.js +1 -0
  46. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Order-m0uoum_X.js +1 -0
  47. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/ScheduleContent-BFuYRCdg.js +1 -0
  48. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/ScheduleContent-legacy-C57h_D4F.js +1 -0
  49. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Settings-Bim_v6Qk.js +1 -0
  50. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/Settings-legacy--XOAgFSe.js +1 -0
  51. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/VehicleMap-CFi1lT_-.js +4 -0
  52. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/VehicleMap-a6kZMJSm.css +1 -0
  53. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/VehicleMap-legacy-DvN0TFdZ.js +5 -0
  54. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/index-Dn7HrE6f.css → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/index-B-8ZqtaE.css +1 -1
  55. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/index-CYkv-WXf.js +265 -0
  56. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/index-legacy-EzXM-nsI.js +351 -0
  57. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-BgwEQWW6-BfKDwSA5.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-BgwEQWW6-Z0UahNeN.js +2 -2
  58. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-BgwEQWW6-legacy-yCIQxmQv.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-BgwEQWW6-legacy-DjxjLUeR.js +1 -1
  59. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-CBzELu-H-cPBKnAaJ.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-CBzELu-H-CyPNfgft.js +2 -2
  60. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-CBzELu-H-legacy-2r1u5Khh.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-CBzELu-H-legacy-BAKv_5SE.js +2 -2
  61. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-CU1SSH8_-P0od39fw.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-CU1SSH8_-CNdgjVXB.js +1 -1
  62. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-CU1SSH8_-legacy-B_i4fNzM.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-CU1SSH8_-legacy-BvckqPS3.js +1 -1
  63. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-CneGxKsZ-legacy-BusG5VYv.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-CneGxKsZ-legacy-BIucGu0r.js +1 -1
  64. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-CneGxKsZ-n-afBYQi.js +3 -0
  65. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-Cwv-vmkN-legacy-DfmkzYoA.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-Cwv-vmkN-legacy-zbWap398.js +1 -1
  66. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-Cwv-vmkN-CWemJXeI.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-Cwv-vmkN-tjrN1zNk.js +2 -2
  67. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-Cz5nLPGT-_FdcV1Vv.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-Cz5nLPGT-DMY47GKb.js +1 -1
  68. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-Cz5nLPGT-legacy-BOhdpZea.js +5 -0
  69. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-D6Ynv7Xh-BEhybWNo.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-D6Ynv7Xh-BRyZz-Or.js +1 -1
  70. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-D6Ynv7Xh-legacy-BI4TMtG3.js → tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/p-D6Ynv7Xh-legacy-BzZfcKZZ.js +1 -1
  71. tesla_cli-4.9.0/src/tesla_cli/api/ui_dist/assets/polyfills-legacy-D1m5vk93.js +1 -0
  72. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/ui_dist/index.html +4 -4
  73. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/data_cmd.py +149 -0
  74. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/serve.py +1 -1
  75. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/automation.py +31 -1
  76. tesla_cli-4.9.0/src/tesla_cli/core/backends/energy_prices.py +169 -0
  77. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/sources.py +9 -0
  78. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_api_routes.py +9 -7
  79. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_sources.py +4 -0
  80. tesla_cli-4.9.0/ui/src/App.tsx +224 -0
  81. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/api/client.ts +233 -8
  82. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/BatteryGauge.tsx +3 -3
  83. tesla_cli-4.9.0/ui/src/components/ErrorBoundary.tsx +31 -0
  84. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/ModelYSilhouette.tsx +1 -1
  85. tesla_cli-4.9.0/ui/src/components/OrderProcessTracker.tsx +473 -0
  86. tesla_cli-4.9.0/ui/src/components/RecentCharges.tsx +57 -0
  87. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/hooks/useDashboardTiles.ts +10 -9
  88. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/hooks/useVehicleData.ts +41 -2
  89. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/Action.tsx +2 -1
  90. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/Analytics.tsx +146 -2
  91. tesla_cli-4.9.0/ui/src/pages/Automations.tsx +579 -0
  92. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/Dashboard.tsx +104 -17
  93. tesla_cli-4.9.0/ui/src/pages/Dossier.tsx +606 -0
  94. tesla_cli-4.9.0/ui/src/pages/Energy.tsx +455 -0
  95. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/Navigation.tsx +2 -2
  96. tesla_cli-4.9.0/ui/src/pages/Order.tsx +373 -0
  97. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/Settings.tsx +111 -3
  98. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/Vehicle.tsx +18 -15
  99. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/vehicle/ScheduleContent.tsx +56 -18
  100. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/theme/variables.css +26 -0
  101. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/uv.lock +2 -1467
  102. tesla_cli-4.8.1/src/tesla_cli/api/routes/charge.py +0 -178
  103. tesla_cli-4.8.1/src/tesla_cli/api/routes/notify.py +0 -86
  104. tesla_cli-4.8.1/src/tesla_cli/api/routes/order.py +0 -25
  105. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/ChargeContent-DB-NWhH1.js +0 -1
  106. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/ChargeContent-legacy-BtQimBgV.js +0 -1
  107. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/ClimateContent-D4CM6N0Z.js +0 -1
  108. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/ControlsContent-D36it6CW.js +0 -1
  109. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/ControlsContent-legacy-ewul7U4S.js +0 -1
  110. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/ScheduleContent-ICcltjam.js +0 -1
  111. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/ScheduleContent-legacy-DAHcE83Y.js +0 -1
  112. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/index-CWH3Fl8L.js +0 -298
  113. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/index-legacy-DTZLiX6K.js +0 -352
  114. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-CneGxKsZ-BSMrC0Tx.js +0 -3
  115. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/p-Cz5nLPGT-legacy-o-dW52P2.js +0 -5
  116. tesla_cli-4.8.1/src/tesla_cli/api/ui_dist/assets/polyfills-legacy-CAPX7zLk.js +0 -4
  117. tesla_cli-4.8.1/ui/src/App.tsx +0 -119
  118. tesla_cli-4.8.1/ui/src/components/RecentCharges.tsx +0 -64
  119. tesla_cli-4.8.1/ui/src/pages/Dossier.tsx +0 -350
  120. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/.dockerignore +0 -0
  121. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/.env.example +0 -0
  122. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  123. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  124. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/.github/workflows/ci.yml +0 -0
  125. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/.github/workflows/publish.yml +0 -0
  126. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/.gitignore +0 -0
  127. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/.python-version +0 -0
  128. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/CONTRIBUTING.md +0 -0
  129. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/Dockerfile +0 -0
  130. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/Formula/tesla-cli.rb +0 -0
  131. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/LICENSE +0 -0
  132. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/Makefile +0 -0
  133. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/README.md +0 -0
  134. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/SECURITY.md +0 -0
  135. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/docker-compose.full.yml +0 -0
  136. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/docker-compose.yml +0 -0
  137. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/docs/api-reference.md +0 -0
  138. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/docs/architecture.md +0 -0
  139. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/docs/configuration.md +0 -0
  140. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/docs/data-sources.md +0 -0
  141. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/docs/research/competitive-analysis.md +0 -0
  142. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/docs/roadmap.md +0 -0
  143. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/docs/user-guide.md +0 -0
  144. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/docs/why-tesla-cli.md +0 -0
  145. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/.claude-plugin/marketplace.json +0 -0
  146. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  147. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/.gitignore +0 -0
  148. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/CHANGELOG.md +0 -0
  149. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/CLAUDE.md +0 -0
  150. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/LICENSE +0 -0
  151. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/README.md +0 -0
  152. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/bin/tesla-check +0 -0
  153. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/docs/design.md +0 -0
  154. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/analytics/SKILL.md +0 -0
  155. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/automations/SKILL.md +0 -0
  156. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/charge/SKILL.md +0 -0
  157. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/control/SKILL.md +0 -0
  158. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/dossier/SKILL.md +0 -0
  159. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/serve/SKILL.md +0 -0
  160. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/setup/SKILL.md +0 -0
  161. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/status/SKILL.md +0 -0
  162. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/telemetry/SKILL.md +0 -0
  163. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/plugins/claude-code/skills/tesla-context/SKILL.md +0 -0
  164. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/__main__.py +0 -0
  165. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/__init__.py +0 -0
  166. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/auth.py +0 -0
  167. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/__init__.py +0 -0
  168. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/auth.py +0 -0
  169. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/climate.py +0 -0
  170. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/colombia.py +0 -0
  171. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/dossier.py +0 -0
  172. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/fleet.py +0 -0
  173. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/geofence.py +0 -0
  174. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/security.py +0 -0
  175. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/sources.py +0 -0
  176. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/routes/teslaMate.py +0 -0
  177. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/ui_dist/favicon.png +0 -0
  178. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/api/ui_dist/manifest.json +0 -0
  179. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/__init__.py +0 -0
  180. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/app.py +0 -0
  181. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/__init__.py +0 -0
  182. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/abrp.py +0 -0
  183. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/automations.py +0 -0
  184. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/ble.py +0 -0
  185. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/charge.py +0 -0
  186. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/climate.py +0 -0
  187. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/config_cmd.py +0 -0
  188. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/dashcam.py +0 -0
  189. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/dossier.py +0 -0
  190. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/energy.py +0 -0
  191. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/geofence.py +0 -0
  192. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/ha.py +0 -0
  193. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/media.py +0 -0
  194. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/mqtt_cmd.py +0 -0
  195. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/notify.py +0 -0
  196. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/order.py +0 -0
  197. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/providers_cmd.py +0 -0
  198. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/scenes.py +0 -0
  199. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/security.py +0 -0
  200. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/service.py +0 -0
  201. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/setup.py +0 -0
  202. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/telemetry.py +0 -0
  203. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/teslaMate.py +0 -0
  204. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/commands/vehicle.py +0 -0
  205. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/i18n.py +0 -0
  206. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/cli/output.py +0 -0
  207. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/__init__.py +0 -0
  208. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/auth/__init__.py +0 -0
  209. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/auth/browser_login.py +0 -0
  210. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/auth/encryption.py +0 -0
  211. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/auth/oauth.py +0 -0
  212. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/auth/portal_scrape.py +0 -0
  213. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/auth/tessie.py +0 -0
  214. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/auth/tokens.py +0 -0
  215. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/__init__.py +0 -0
  216. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/base.py +0 -0
  217. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/dossier.py +0 -0
  218. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/energy.py +0 -0
  219. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/fleet.py +0 -0
  220. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/fleet_signed.py +0 -0
  221. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/fleet_telemetry.py +0 -0
  222. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/http.py +0 -0
  223. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/order.py +0 -0
  224. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/owner.py +0 -0
  225. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/runt.py +0 -0
  226. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/simit.py +0 -0
  227. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/teslaMate.py +0 -0
  228. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/backends/tessie.py +0 -0
  229. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/config.py +0 -0
  230. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/exceptions.py +0 -0
  231. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/models/__init__.py +0 -0
  232. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/models/automation.py +0 -0
  233. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/models/charge.py +0 -0
  234. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/models/climate.py +0 -0
  235. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/models/dossier.py +0 -0
  236. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/models/drive.py +0 -0
  237. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/models/energy.py +0 -0
  238. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/models/order.py +0 -0
  239. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/models/vehicle.py +0 -0
  240. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/__init__.py +0 -0
  241. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/base.py +0 -0
  242. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/impl/__init__.py +0 -0
  243. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/impl/abrp.py +0 -0
  244. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/impl/apprise_notify.py +0 -0
  245. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/impl/ble.py +0 -0
  246. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/impl/ha.py +0 -0
  247. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/impl/mqtt.py +0 -0
  248. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/impl/teslaMate.py +0 -0
  249. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/impl/vehicle_api.py +0 -0
  250. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/loader.py +0 -0
  251. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/core/providers/registry.py +0 -0
  252. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/endpoints.json +0 -0
  253. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/infra/__init__.py +0 -0
  254. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/infra/fleet_telemetry_stack.py +0 -0
  255. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/infra/teslamate_stack.py +0 -0
  256. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/src/tesla_cli/py.typed +0 -0
  257. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tesla-config-backup.json +0 -0
  258. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/__init__.py +0 -0
  259. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/conftest.py +0 -0
  260. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_api_routes_new.py +0 -0
  261. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_auth.py +0 -0
  262. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_browser_login.py +0 -0
  263. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_commands.py +0 -0
  264. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_models.py +0 -0
  265. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_new_commands.py +0 -0
  266. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_order_backend.py +0 -0
  267. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_pipeline.py +0 -0
  268. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_providers.py +0 -0
  269. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_providers_new.py +0 -0
  270. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_runt.py +0 -0
  271. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_runt_integration.py +0 -0
  272. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_server.py +0 -0
  273. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_simit.py +0 -0
  274. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_simit_integration.py +0 -0
  275. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_teslamate_stack.py +0 -0
  276. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_v260.py +0 -0
  277. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_v270.py +0 -0
  278. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_v280.py +0 -0
  279. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_v290.py +0 -0
  280. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_v300.py +0 -0
  281. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_v310.py +0 -0
  282. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_v320.py +0 -0
  283. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_v330.py +0 -0
  284. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/tests/test_v340.py +0 -0
  285. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/.browserslistrc +0 -0
  286. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/.gitignore +0 -0
  287. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/cypress/e2e/test.cy.ts +0 -0
  288. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/cypress/fixtures/example.json +0 -0
  289. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/cypress/support/commands.ts +0 -0
  290. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/cypress/support/e2e.ts +0 -0
  291. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/cypress.config.ts +0 -0
  292. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/eslint.config.js +0 -0
  293. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/index.html +0 -0
  294. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/ionic.config.json +0 -0
  295. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/ionic.starter.json +0 -0
  296. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/package-lock.json +0 -0
  297. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/package.json +0 -0
  298. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/public/favicon.png +0 -0
  299. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/public/manifest.json +0 -0
  300. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/App.test.tsx +0 -0
  301. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/CommandButton.tsx +0 -0
  302. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/ExploreContainer.css +0 -0
  303. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/ExploreContainer.tsx +0 -0
  304. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/SeatHeaterGrid.tsx +0 -0
  305. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/StatusBadge.tsx +0 -0
  306. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/VehicleMap.tsx +0 -0
  307. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/dossier/CollapsibleSection.tsx +0 -0
  308. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/dossier/LogisticsCard.tsx +0 -0
  309. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/dossier/OptionCodesPills.tsx +0 -0
  310. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/dossier/RuntCard.tsx +0 -0
  311. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/dossier/SimitCard.tsx +0 -0
  312. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/dossier/SpecsGrid.tsx +0 -0
  313. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/dossier/StatusPipeline.tsx +0 -0
  314. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/icons/Icons.tsx +0 -0
  315. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/components/icons/Spinner.tsx +0 -0
  316. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/hooks/useDossierData.ts +0 -0
  317. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/main.tsx +0 -0
  318. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/Home.css +0 -0
  319. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/vehicle/ChargeContent.tsx +0 -0
  320. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/vehicle/ClimateContent.tsx +0 -0
  321. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/pages/vehicle/ControlsContent.tsx +0 -0
  322. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/setupTests.ts +0 -0
  323. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/src/vite-env.d.ts +0 -0
  324. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/tsconfig.json +0 -0
  325. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/tsconfig.node.json +0 -0
  326. {tesla_cli-4.8.1 → tesla_cli-4.9.0}/ui/vite.config.ts +0 -0
@@ -5,6 +5,44 @@ 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.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.9.0] - 2026-04-06
9
+
10
+ ### Dashboard
11
+ - **Dedicated Order page** with 15-step financing/delivery tracker
12
+ - **Energy page** — Powerwall controls, city tariff comparison, cost calculator
13
+ - **Automations page** — CRUD rules, quick setup, test/toggle/delete
14
+ - **Notification history** timeline in Settings
15
+ - **Offline mode** — cached vehicle data when server is down
16
+ - **Mobile responsive** — CSS breakpoints for phones/tablets
17
+ - **Scene cards** on dashboard (Morning/Goodnight/Trip)
18
+ - **Code-split routes** — lazy-loaded pages for faster initial load
19
+
20
+ ### API (30+ new endpoints)
21
+ - Energy management: sites, status, backup, mode, storm
22
+ - Automations: CRUD, enable/disable, test, status
23
+ - Charge scheduling + analytics: sessions, cost, forecast
24
+ - Service: history, appointments, reminders
25
+ - Scenes: list + execute
26
+ - ABRP, BLE, MQTT, Dashcam endpoints
27
+ - Energy tariffs: by city/estrato + vehicle location
28
+ - 429 rate-limit retry with Retry-After
29
+
30
+ ### CLI
31
+ - BLE key management (enroll, list, remove, state reads)
32
+ - Safety Score + Service scheduling (first-mover)
33
+ - EV vs gas savings calculator
34
+ - Location-based charge/precondition schedules
35
+ - Country-aware sources (9 countries, 35+ sources)
36
+ - Dashcam processing (list/process/export)
37
+ - Webhook automations (IFTTT/HomeKit/Google Home)
38
+ - Energy tariffs command
39
+
40
+ ### Quality
41
+ - 17 UI bugs fixed (critical crashes, color errors, missing guards)
42
+ - Error boundary + React.Suspense on all lazy routes
43
+ - Flaky test fixed permanently
44
+ - 1682 tests passing
45
+
8
46
  ## [4.8.0] - 2026-04-05
9
47
 
10
48
  ### New Features
@@ -4,7 +4,7 @@
4
4
 
5
5
  Full-stack Tesla management platform: CLI (Typer) + REST API (FastAPI) + Web Dashboard (React/Ionic). Tracks orders, controls vehicles, aggregates data from 15+ sources, integrates with TeslaMate/MQTT/HA/ABRP.
6
6
 
7
- **Version**: v4.8.0 | **Python**: 3.12+ | **Package manager**: uv | **Tests**: 1679
7
+ **Version**: v4.9.0 | **Python**: 3.12+ | **Package manager**: uv | **Tests**: 1682
8
8
 
9
9
  ## Architecture (quick reference)
10
10
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tesla-cli
3
- Version: 4.8.1
3
+ Version: 4.9.0
4
4
  Summary: CLI tool for Tesla order tracking and vehicle control
5
5
  Project-URL: Homepage, https://github.com/dacrypt/tesla
6
6
  Project-URL: Repository, https://github.com/dacrypt/tesla
@@ -35,10 +35,6 @@ Requires-Dist: pytest>=8; extra == 'dev'
35
35
  Requires-Dist: ruff>=0.9; extra == 'dev'
36
36
  Provides-Extra: fleet
37
37
  Requires-Dist: tesla-fleet-api>=1.0; extra == 'fleet'
38
- Provides-Extra: ocr
39
- Requires-Dist: easyocr>=1.7; extra == 'ocr'
40
- Requires-Dist: paddleocr>=3.0; extra == 'ocr'
41
- Requires-Dist: paddlepaddle>=3.0; extra == 'ocr'
42
38
  Provides-Extra: pdf
43
39
  Requires-Dist: fpdf2>=2.7; extra == 'pdf'
44
40
  Provides-Extra: query
@@ -0,0 +1,39 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ cd /Users/david/dev/dacrypt/tesla
4
+
5
+ if [ -x .venv/bin/python3 ]; then
6
+ PY=.venv/bin/python3
7
+ else
8
+ PY=python3
9
+ fi
10
+
11
+ rm -f history/last-changes.json history/pending-alert.txt
12
+
13
+ "$PY" refresh-mission-control.py
14
+ CHANGE_OUTPUT=$("$PY" change-detector.py 2>&1 || true)
15
+ echo "$CHANGE_OUTPUT"
16
+ bash build-activity-log.sh
17
+
18
+ if echo "$CHANGE_OUTPUT" | grep -q "✅ No changes detected"; then
19
+ echo "NO_CHANGES"
20
+ exit 0
21
+ fi
22
+
23
+ if [ -f history/last-changes.json ]; then
24
+ python3 - <<'PY'
25
+ import json
26
+ from pathlib import Path
27
+ p = Path('history/last-changes.json')
28
+ if not p.exists():
29
+ print('NO_CHANGES')
30
+ raise SystemExit(0)
31
+ obj = json.loads(p.read_text())
32
+ if obj.get('has_changes'):
33
+ print(obj.get('alert','').strip())
34
+ else:
35
+ print('NO_CHANGES')
36
+ PY
37
+ else
38
+ echo "NO_CHANGES"
39
+ fi
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: energy
3
+ description: >
4
+ Tesla energy management — Powerwall status, Solar production, electricity
5
+ tariffs by city, backup reserve, operation mode, storm watch.
6
+ argument-hint: "[query: status|tariffs|backup|mode|storm|savings]"
7
+ allowed-tools: Bash(tesla *)
8
+ level: 2
9
+ ---
10
+
11
+ # Tesla Energy Management
12
+
13
+ Monitor and control Powerwall, solar production, and electricity tariffs.
14
+
15
+ ## Powerwall Status
16
+
17
+ ```bash
18
+ tesla energy status # Powerwall charge %, solar W, grid W, home W
19
+ tesla energy status --oneline # compact: 🔋 82% | ☀️ 3.2kW solar | 🏠 1.1kW home
20
+ ```
21
+
22
+ ## Tariffs by City
23
+
24
+ ```bash
25
+ tesla data energia --ciudad bogota --estrato 4 # tariff for Bogotá estrato 4
26
+ tesla data energia --ciudad medellin --estrato 3 # Medellín estrato 3
27
+ tesla data energia # use vehicle location automatically
28
+ ```
29
+
30
+ Shows COP/kWh rate, tier breakdown, and estimated monthly cost.
31
+
32
+ ## Backup Reserve
33
+
34
+ ```bash
35
+ tesla energy backup # show current backup reserve %
36
+ tesla energy backup 30 # set backup reserve to 30%
37
+ ```
38
+
39
+ ## Operation Mode
40
+
41
+ ```bash
42
+ tesla energy mode # show current mode
43
+ tesla energy mode self_consumption # maximize solar self-consumption
44
+ tesla energy mode autonomous # Time-Based Control (TOU)
45
+ tesla energy mode backup # full backup mode
46
+ ```
47
+
48
+ ## Storm Watch
49
+
50
+ ```bash
51
+ tesla energy storm --on # enable Storm Watch (charge to 100%)
52
+ tesla energy storm --off # disable Storm Watch
53
+ ```
54
+
55
+ ## Savings Calculator
56
+
57
+ ```bash
58
+ tesla charge savings # EV vs gas savings summary
59
+ tesla charge savings --months 6 # last 6 months comparison
60
+ ```
61
+
62
+ ## Response Guidelines
63
+
64
+ - If the CLI is not configured, **stop and tell the user to run `/tesla:setup`** — never auto-configure
65
+ - Start with Powerwall % and current solar/grid/home power flows
66
+ - For tariff queries: show rate in COP/kWh and compare to grid cost
67
+ - For backup/mode changes: confirm the new setting after applying
68
+ - For `$ARGUMENTS`:
69
+ - "status" / no args → `tesla energy status`
70
+ - "tariffs" / "precio" / "estrato" → `tesla data energia`
71
+ - "backup" → `tesla energy backup`
72
+ - "mode" / "modo" → `tesla energy mode`
73
+ - "storm" → `tesla energy storm`
74
+ - "savings" / "ahorro" → `tesla charge savings`
@@ -25,7 +25,7 @@ tesla order delivery # delivery appointment (date, time, location)
25
25
 
26
26
  ```bash
27
27
  tesla order eta # delivery ETA (best/typical/worst estimates)
28
- tesla order gates # 13-gate delivery journey tracker
28
+ tesla order gates # 15-step financing/delivery journey tracker (gates 1–15)
29
29
  tesla order estimate # community-based delivery date estimation
30
30
  tesla order stores # nearby Tesla stores/Service Centers
31
31
  tesla order stores --near 4.6,-74.1 # stores near coordinates
@@ -73,7 +73,7 @@ tesla order documents --download # download all to ~/.tesla-cli/documents/
73
73
 
74
74
  - If the CLI is not configured, **stop and tell the user to run `/tesla:setup`** — never auto-configure
75
75
  - Start with the **current order status** and **delivery date** if available
76
- - Show the gate progress (which of 13 gates have been passed)
76
+ - Show the gate progress (which of the 15 financing/delivery steps have been passed)
77
77
  - If the car hasn't been delivered yet, include ETA estimates
78
78
  - If delivery is upcoming, suggest the checklist
79
79
  - For `$ARGUMENTS`:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tesla-cli"
3
- version = "4.8.1"
3
+ version = "4.9.0"
4
4
  description = "CLI tool for Tesla order tracking and vehicle control"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -36,7 +36,6 @@ teslaMate = ["psycopg2-binary>=2.9"]
36
36
  pdf = ["fpdf2>=2.7"]
37
37
  serve = ["fastapi>=0.110", "uvicorn[standard]>=0.29"]
38
38
  query = ["openquery"]
39
- ocr = ["paddlepaddle>=3.0", "paddleocr>=3.0", "easyocr>=1.7"]
40
39
  dev = ["pytest>=8", "pytest-httpx>=0.35", "ruff>=0.9"]
41
40
 
42
41
  [project.scripts]
@@ -1,3 +1,3 @@
1
1
  """Tesla CLI - Order tracking and vehicle control."""
2
2
 
3
- __version__ = "4.0.0"
3
+ __version__ = "4.8.1"
@@ -193,13 +193,19 @@ def _register_middleware(app: FastAPI) -> None:
193
193
 
194
194
  def _register_routes(app: FastAPI) -> None:
195
195
  """Include all API routers."""
196
+ from tesla_cli.api.routes.abrp import router as abrp_router
196
197
  from tesla_cli.api.routes.auth import router as auth_router
198
+ from tesla_cli.api.routes.automations import router as automations_router
199
+ from tesla_cli.api.routes.ble import router as ble_router
197
200
  from tesla_cli.api.routes.charge import router as charge_router
198
201
  from tesla_cli.api.routes.climate import router as climate_router
199
202
  from tesla_cli.api.routes.colombia import router as colombia_router
203
+ from tesla_cli.api.routes.dashcam import router as dashcam_router
200
204
  from tesla_cli.api.routes.dossier import router as dossier_router
205
+ from tesla_cli.api.routes.energy_prices import router as energy_prices_router
201
206
  from tesla_cli.api.routes.fleet import router as fleet_router
202
207
  from tesla_cli.api.routes.geofence import router as geofence_router
208
+ from tesla_cli.api.routes.mqtt import router as mqtt_router
203
209
  from tesla_cli.api.routes.notify import router as notify_router
204
210
  from tesla_cli.api.routes.order import router as order_router
205
211
  from tesla_cli.api.routes.security import router as security_router
@@ -210,6 +216,7 @@ def _register_routes(app: FastAPI) -> None:
210
216
  app.include_router(auth_router, prefix="/api/auth", tags=["Auth"])
211
217
  app.include_router(sources_router, prefix="/api/sources", tags=["Sources"])
212
218
  app.include_router(colombia_router, prefix="/api/co", tags=["Colombia"])
219
+ app.include_router(energy_prices_router, prefix="/api/energy", tags=["Energy"])
213
220
  app.include_router(vehicle_router, prefix="/api/vehicle", tags=["Vehicle"])
214
221
  app.include_router(charge_router, prefix="/api/charge", tags=["Charge"])
215
222
  app.include_router(climate_router, prefix="/api/climate", tags=["Climate"])
@@ -220,6 +227,76 @@ def _register_routes(app: FastAPI) -> None:
220
227
  app.include_router(geofence_router, prefix="/api/geofences", tags=["Geofences"])
221
228
  app.include_router(teslaMate_router, prefix="/api/teslaMate", tags=["TeslaMate"])
222
229
  app.include_router(fleet_router, prefix="/api/fleet", tags=["Fleet"])
230
+ app.include_router(automations_router, prefix="/api/automations", tags=["Automations"])
231
+ app.include_router(abrp_router, prefix="/api/abrp", tags=["ABRP"])
232
+ app.include_router(ble_router, prefix="/api/ble", tags=["BLE"])
233
+ app.include_router(mqtt_router, prefix="/api/mqtt", tags=["MQTT"])
234
+ app.include_router(dashcam_router, prefix="/api/dashcam", tags=["Dashcam"])
235
+
236
+
237
+ def _build_health_deep(result: dict) -> dict:
238
+ """Extend health result with deep diagnostics."""
239
+ from tesla_cli.core.auth import tokens
240
+
241
+ cfg = load_config()
242
+ result["backend"] = cfg.general.backend
243
+ result["vin_configured"] = bool(cfg.general.default_vin)
244
+ result["has_auth_token"] = tokens.has_token(tokens.ORDER_REFRESH_TOKEN)
245
+ result["telemetry_enabled"] = cfg.telemetry.enabled
246
+ result["teslamate_managed"] = cfg.teslaMate.managed
247
+ return result
248
+
249
+
250
+ def _build_vehicles_list(cfg) -> list:
251
+ """Build the vehicles list from config (default VIN + aliases)."""
252
+ vehicles = []
253
+ default = cfg.general.default_vin
254
+ if default:
255
+ vehicles.append({"vin": default, "alias": "default", "is_default": True})
256
+ for alias, vin in cfg.vehicles.aliases.items():
257
+ if vin != default:
258
+ vehicles.append({"vin": vin, "alias": alias, "is_default": False})
259
+ return vehicles
260
+
261
+
262
+ def _build_config_response(cfg) -> dict:
263
+ """Serialize public config fields for /api/config."""
264
+ return {
265
+ "backend": cfg.general.backend,
266
+ "default_vin": cfg.general.default_vin,
267
+ "cost_per_kwh": cfg.general.cost_per_kwh,
268
+ "teslaMate_url": bool(cfg.teslaMate.database_url),
269
+ "ha_url": cfg.home_assistant.url,
270
+ "abrp_configured": bool(cfg.abrp.user_token),
271
+ "geofences": list(cfg.geofences.zones.keys()),
272
+ "notifications": cfg.notifications.enabled,
273
+ "vehicles": cfg.vehicles.aliases,
274
+ "auth_enabled": bool(cfg.server.api_key),
275
+ }
276
+
277
+
278
+ def _build_provider_capabilities() -> dict:
279
+ """Build capability map from the provider registry."""
280
+ from tesla_cli.core.providers import get_registry
281
+ from tesla_cli.core.providers.base import Capability
282
+
283
+ registry = get_registry()
284
+ out = {}
285
+ for cap in sorted(Capability.all()):
286
+ available = [p.name for p in registry.for_capability(cap)]
287
+ all_p = [p.name for p in registry.for_capability(cap, available_only=False)]
288
+ out[cap] = {"available": available, "all": all_p}
289
+ return out
290
+
291
+
292
+ def _build_config_validation(cfg) -> dict:
293
+ """Run config checks and return a structured validation result."""
294
+ from tesla_cli.cli.commands.config_cmd import _run_config_checks
295
+
296
+ checks = _run_config_checks(cfg)
297
+ errors = sum(1 for c in checks if c["status"] == "error")
298
+ warnings = sum(1 for c in checks if c["status"] == "warn")
299
+ return {"valid": errors == 0, "errors": errors, "warnings": warnings, "checks": checks}
223
300
 
224
301
 
225
302
  def _register_system_endpoints(app: FastAPI) -> None:
@@ -235,14 +312,7 @@ def _register_system_endpoints(app: FastAPI) -> None:
235
312
  """
236
313
  result: dict = {"status": "ok", "version": __version__}
237
314
  if deep:
238
- from tesla_cli.core.auth import tokens
239
-
240
- cfg = load_config()
241
- result["backend"] = cfg.general.backend
242
- result["vin_configured"] = bool(cfg.general.default_vin)
243
- result["has_auth_token"] = tokens.has_token(tokens.ORDER_REFRESH_TOKEN)
244
- result["telemetry_enabled"] = cfg.telemetry.enabled
245
- result["teslamate_managed"] = cfg.teslaMate.managed
315
+ _build_health_deep(result)
246
316
  return result
247
317
 
248
318
  @app.get("/api/status", tags=["System"])
@@ -258,33 +328,11 @@ def _register_system_endpoints(app: FastAPI) -> None:
258
328
  @app.get("/api/vehicles", tags=["System"])
259
329
  def api_vehicles() -> list:
260
330
  """List all configured vehicles (aliases + default VIN)."""
261
- cfg = load_config()
262
- vehicles = []
263
- # Always include the default VIN first
264
- default = cfg.general.default_vin
265
- if default:
266
- vehicles.append({"vin": default, "alias": "default", "is_default": True})
267
- # Add any aliases that are different from the default
268
- for alias, vin in cfg.vehicles.aliases.items():
269
- if vin != default:
270
- vehicles.append({"vin": vin, "alias": alias, "is_default": False})
271
- return vehicles
331
+ return _build_vehicles_list(load_config())
272
332
 
273
333
  @app.get("/api/config", tags=["System"])
274
334
  def api_config() -> dict:
275
- cfg = load_config()
276
- return {
277
- "backend": cfg.general.backend,
278
- "default_vin": cfg.general.default_vin,
279
- "cost_per_kwh": cfg.general.cost_per_kwh,
280
- "teslaMate_url": bool(cfg.teslaMate.database_url),
281
- "ha_url": cfg.home_assistant.url,
282
- "abrp_configured": bool(cfg.abrp.user_token),
283
- "geofences": list(cfg.geofences.zones.keys()),
284
- "notifications": cfg.notifications.enabled,
285
- "vehicles": cfg.vehicles.aliases,
286
- "auth_enabled": bool(cfg.server.api_key),
287
- }
335
+ return _build_config_response(load_config())
288
336
 
289
337
  @app.get("/api/providers", tags=["System"])
290
338
  def api_providers() -> list:
@@ -296,16 +344,7 @@ def _register_system_endpoints(app: FastAPI) -> None:
296
344
  @app.get("/api/providers/capabilities", tags=["System"])
297
345
  def api_provider_capabilities() -> dict:
298
346
  """Capability map — which providers serve which capabilities."""
299
- from tesla_cli.core.providers import get_registry
300
- from tesla_cli.core.providers.base import Capability
301
-
302
- registry = get_registry()
303
- out = {}
304
- for cap in sorted(Capability.all()):
305
- available = [p.name for p in registry.for_capability(cap)]
306
- all_p = [p.name for p in registry.for_capability(cap, available_only=False)]
307
- out[cap] = {"available": available, "all": all_p}
308
- return out
347
+ return _build_provider_capabilities()
309
348
 
310
349
  @app.get("/api/config/validate", tags=["System"])
311
350
  def api_config_validate() -> dict:
@@ -313,13 +352,7 @@ def _register_system_endpoints(app: FastAPI) -> None:
313
352
 
314
353
  Returns {valid, errors, warnings, checks[]} suitable for a dashboard health widget.
315
354
  """
316
- from tesla_cli.cli.commands.config_cmd import _run_config_checks
317
-
318
- cfg = load_config()
319
- checks = _run_config_checks(cfg)
320
- errors = sum(1 for c in checks if c["status"] == "error")
321
- warnings = sum(1 for c in checks if c["status"] == "warn")
322
- return {"valid": errors == 0, "errors": errors, "warnings": warnings, "checks": checks}
355
+ return _build_config_validation(load_config())
323
356
 
324
357
 
325
358
  def _register_metrics(app: FastAPI) -> None:
@@ -407,6 +440,68 @@ def _register_metrics(app: FastAPI) -> None:
407
440
  return PlainTextResponse("".join(lines), media_type="text/plain; version=0.0.4")
408
441
 
409
442
 
443
+ def _sse_topic_events(data: dict, ts: int, topic_set: set) -> list[str]:
444
+ """Build optional per-topic SSE event strings for battery/climate/drive/location."""
445
+ want_battery = "battery" in topic_set
446
+ want_climate = "climate" in topic_set
447
+ want_drive = "drive" in topic_set
448
+ want_location = "location" in topic_set
449
+
450
+ events = []
451
+ if want_battery:
452
+ cs = data.get("charge_state") or {}
453
+ events.append(f"event: battery\ndata: {json.dumps({'ts': ts, 'data': _sanitize(cs)})}\n\n")
454
+ if want_climate:
455
+ cl = data.get("climate_state") or {}
456
+ events.append(f"event: climate\ndata: {json.dumps({'ts': ts, 'data': _sanitize(cl)})}\n\n")
457
+ if want_drive:
458
+ ds = data.get("drive_state") or {}
459
+ events.append(f"event: drive\ndata: {json.dumps({'ts': ts, 'data': _sanitize(ds)})}\n\n")
460
+ if want_location:
461
+ ds = data.get("drive_state") or {}
462
+ loc = {
463
+ "lat": ds.get("latitude"),
464
+ "lon": ds.get("longitude"),
465
+ "heading": ds.get("heading"),
466
+ "speed": ds.get("speed"),
467
+ }
468
+ events.append(f"event: location\ndata: {json.dumps({'ts': ts, 'data': loc})}\n\n")
469
+ return events
470
+
471
+
472
+ def _sse_geofence_events(data: dict, ts: int, geofence_state: dict[str, bool]) -> list[str]:
473
+ """Compute geofence enter/exit SSE events from current vehicle position."""
474
+ drive = data.get("drive_state") or data.get("response", {}).get("drive_state", {})
475
+ lat = drive.get("latitude") if isinstance(drive, dict) else None
476
+ lon = drive.get("longitude") if isinstance(drive, dict) else None
477
+ if lat is None or lon is None:
478
+ return []
479
+
480
+ events = []
481
+ reload_cfg = load_config()
482
+ for name, zone in reload_cfg.geofences.zones.items():
483
+ dist = _haversine_km(lat, lon, zone["lat"], zone["lon"])
484
+ inside = dist <= zone.get("radius_km", 0.5)
485
+ was_inside = geofence_state.get(name)
486
+ if was_inside is None:
487
+ geofence_state[name] = inside
488
+ elif inside != was_inside:
489
+ geofence_state[name] = inside
490
+ event = "enter" if inside else "exit"
491
+ gf_payload = json.dumps(
492
+ {
493
+ "ts": ts,
494
+ "zone": name,
495
+ "event": event,
496
+ "lat": lat,
497
+ "lon": lon,
498
+ "dist_km": round(dist, 3),
499
+ }
500
+ )
501
+ events.append(f"event: geofence\ndata: {gf_payload}\n\n")
502
+ return events
503
+
504
+
410
505
  def _register_sse_stream(app: FastAPI) -> None:
411
506
  """Register the real-time SSE vehicle stream endpoint."""
412
507
 
@@ -435,15 +530,9 @@ def _register_sse_stream(app: FastAPI) -> None:
435
530
  cfg = load_config()
436
531
  v = resolve_vin(cfg, app.state.override_vin)
437
532
  topic_set = {t.strip() for t in topics.split(",") if t.strip()}
438
- want_geofence = "geofence" in topic_set
439
- want_battery = "battery" in topic_set
440
- want_climate = "climate" in topic_set
441
- want_drive = "drive" in topic_set
442
- want_location = "location" in topic_set
443
533
  geofence_state: dict[str, bool] = {} # zone_name → was_inside
444
534
 
445
535
  async def _generate():
446
- nonlocal geofence_state
447
536
  backend = get_vehicle_backend(cfg)
448
537
  while True:
449
538
  if await request.is_disconnected():
@@ -453,69 +542,20 @@ def _register_sse_stream(app: FastAPI) -> None:
453
542
  None, lambda: backend.get_vehicle_data(v)
454
543
  )
455
544
  ts = int(time.time())
456
- payload = json.dumps(
457
- {
458
- "ts": ts,
459
- "data": _sanitize(data),
460
- }
461
- )
545
+ payload = json.dumps({"ts": ts, "data": _sanitize(data)})
462
546
  yield f"event: vehicle\ndata: {payload}\n\n"
463
547
 
464
- if want_battery:
465
- cs = data.get("charge_state") or {}
466
- yield f"event: battery\ndata: {json.dumps({'ts': ts, 'data': _sanitize(cs)})}\n\n"
467
-
468
- if want_climate:
469
- cl = data.get("climate_state") or {}
470
- yield f"event: climate\ndata: {json.dumps({'ts': ts, 'data': _sanitize(cl)})}\n\n"
471
-
472
- if want_drive:
473
- ds = data.get("drive_state") or {}
474
- yield f"event: drive\ndata: {json.dumps({'ts': ts, 'data': _sanitize(ds)})}\n\n"
475
-
476
- if want_location:
477
- ds = data.get("drive_state") or {}
478
- loc = {
479
- "lat": ds.get("latitude"),
480
- "lon": ds.get("longitude"),
481
- "heading": ds.get("heading"),
482
- "speed": ds.get("speed"),
483
- }
484
- yield f"event: location\ndata: {json.dumps({'ts': ts, 'data': loc})}\n\n"
548
+ for ev in _sse_topic_events(data, ts, topic_set):
549
+ yield ev
485
550
 
486
551
  if fanout:
487
552
  await asyncio.get_event_loop().run_in_executor(
488
553
  None, _fanout_telemetry, data, v, cfg
489
554
  )
490
555
 
491
- if want_geofence:
492
- drive = data.get("drive_state") or data.get("response", {}).get(
493
- "drive_state", {}
494
- )
495
- lat = drive.get("latitude") if isinstance(drive, dict) else None
496
- lon = drive.get("longitude") if isinstance(drive, dict) else None
497
- if lat is not None and lon is not None:
498
- reload_cfg = load_config()
499
- for name, zone in reload_cfg.geofences.zones.items():
500
- dist = _haversine_km(lat, lon, zone["lat"], zone["lon"])
501
- inside = dist <= zone.get("radius_km", 0.5)
502
- was_inside = geofence_state.get(name)
503
- if was_inside is None:
504
- geofence_state[name] = inside
505
- elif inside != was_inside:
506
- geofence_state[name] = inside
507
- event = "enter" if inside else "exit"
508
- gf_payload = json.dumps(
509
- {
510
- "ts": ts,
511
- "zone": name,
512
- "event": event,
513
- "lat": lat,
514
- "lon": lon,
515
- "dist_km": round(dist, 3),
516
- }
517
- )
518
- yield f"event: geofence\ndata: {gf_payload}\n\n"
556
+ if "geofence" in topic_set:
557
+ for ev in _sse_geofence_events(data, ts, geofence_state):
558
+ yield ev
519
559
 
520
560
  except Exception as exc: # noqa: BLE001
521
561
  yield f"event: vehicle\ndata: {json.dumps({'error': str(exc)})}\n\n"
@@ -0,0 +1,73 @@
1
+ """ABRP API routes: /api/abrp/*"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from fastapi import APIRouter, HTTPException, Request
6
+
7
+ from tesla_cli.core.config import load_config, resolve_vin
8
+
9
+ router = APIRouter()
10
+
11
+ _ABRP_API = "https://api.iternio.com/1/tlm/send"
12
+
13
+
14
+ @router.get("/status")
15
+ def abrp_status() -> dict:
16
+ """ABRP connection status and configuration."""
17
+ cfg = load_config()
18
+ return {
19
+ "user_token_set": bool(cfg.abrp.user_token),
20
+ "api_key_set": bool(cfg.abrp.api_key),
21
+ "configured": bool(cfg.abrp.user_token),
22
+ "abrp_api": _ABRP_API,
23
+ }
24
+
25
+
26
+ @router.get("/config")
27
+ def abrp_config() -> dict:
28
+ """Get ABRP configuration (api_key configured, user_token set)."""
29
+ cfg = load_config()
30
+ return {
31
+ "user_token_set": bool(cfg.abrp.user_token),
32
+ "api_key_set": bool(cfg.abrp.api_key),
33
+ "abrp_api": _ABRP_API,
34
+ }
35
+
36
+
37
+ @router.post("/send")
38
+ def abrp_send(request: Request) -> dict:
39
+ """Send current vehicle telemetry to ABRP."""
40
+ cfg = load_config()
41
+
42
+ if not cfg.abrp.user_token:
43
+ raise HTTPException(
44
+ status_code=400,
45
+ detail="ABRP user token not configured. Run: tesla config set abrp-user-token <TOKEN>",
46
+ )
47
+
48
+ try:
49
+ from tesla_cli.core.backends import get_vehicle_backend
50
+
51
+ v = resolve_vin(cfg, request.app.state.override_vin)
52
+ backend = get_vehicle_backend(cfg)
53
+ data = backend.get_vehicle_data(v)
54
+ except Exception as exc:
55
+ raise HTTPException(status_code=502, detail=f"Failed to get vehicle data: {exc}")
56
+
57
+ try:
58
+ from tesla_cli.core.providers.impl.abrp import AbrpProvider
59
+
60
+ provider = AbrpProvider(cfg)
61
+ result = provider.execute("push", data=data)
62
+ if not result.ok:
63
+ raise HTTPException(status_code=502, detail=result.error or "ABRP push failed")
64
+ return {
65
+ "ok": True,
66
+ "telemetry": result.data.get("tlm") if result.data else {},
67
+ "abrp_response": result.data.get("response") if result.data else {},
68
+ "latency_ms": result.latency_ms,
69
+ }
70
+ except HTTPException:
71
+ raise
72
+ except Exception as exc:
73
+ raise HTTPException(status_code=502, detail=str(exc))