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.
- tescmd-0.2.0/.github/workflows/publish.yml +19 -0
- tescmd-0.2.0/.github/workflows/test.yml +23 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/CHANGELOG.md +31 -1
- {tescmd-0.1.2 → tescmd-0.2.0}/CLAUDE.md +36 -7
- {tescmd-0.1.2 → tescmd-0.2.0}/PKG-INFO +72 -35
- {tescmd-0.1.2 → tescmd-0.2.0}/README.md +68 -34
- {tescmd-0.1.2 → tescmd-0.2.0}/docs/architecture.md +27 -3
- {tescmd-0.1.2 → tescmd-0.2.0}/docs/bot-integration.md +38 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/docs/commands.md +69 -3
- {tescmd-0.1.2 → tescmd-0.2.0}/docs/development.md +20 -22
- tescmd-0.2.0/docs/faq.md +108 -0
- tescmd-0.2.0/docs/setup.md +187 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/pyproject.toml +13 -1
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/__init__.py +1 -1
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/client.py +8 -1
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/errors.py +8 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/vehicle.py +19 -1
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cache/response_cache.py +3 -2
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/auth.py +30 -2
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/key.py +149 -14
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/main.py +44 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/setup.py +230 -22
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/vehicle.py +464 -1
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/crypto/__init__.py +3 -1
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/crypto/ecdh.py +9 -0
- tescmd-0.2.0/src/tescmd/crypto/schnorr.py +191 -0
- tescmd-0.2.0/src/tescmd/deploy/tailscale_serve.py +154 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/__init__.py +0 -2
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/auth.py +19 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/config.py +1 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/energy.py +0 -9
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/session.py +10 -3
- tescmd-0.2.0/src/tescmd/telemetry/__init__.py +19 -0
- tescmd-0.2.0/src/tescmd/telemetry/dashboard.py +227 -0
- tescmd-0.2.0/src/tescmd/telemetry/decoder.py +284 -0
- tescmd-0.2.0/src/tescmd/telemetry/fields.py +248 -0
- tescmd-0.2.0/src/tescmd/telemetry/flatbuf.py +162 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/__init__.py +4 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_alert.proto +31 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_alert_pb2.py +42 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_alert_pb2.pyi +44 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_connectivity.proto +23 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_connectivity_pb2.py +40 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_connectivity_pb2.pyi +33 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_data.proto +768 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_data_pb2.py +136 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_data_pb2.pyi +1336 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_error.proto +23 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_error_pb2.py +44 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_error_pb2.pyi +39 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_metric.proto +22 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_metric_pb2.py +44 -0
- tescmd-0.2.0/src/tescmd/telemetry/protos/vehicle_metric_pb2.pyi +37 -0
- tescmd-0.2.0/src/tescmd/telemetry/server.py +293 -0
- tescmd-0.2.0/src/tescmd/telemetry/tailscale.py +300 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_cli_integration.py +1 -1
- tescmd-0.2.0/tests/cli/test_e2e_smoke.py +747 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_key.py +169 -5
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_main_errors.py +7 -3
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_setup.py +256 -0
- tescmd-0.2.0/tests/crypto/test_schnorr.py +245 -0
- tescmd-0.2.0/tests/deploy/test_tailscale_serve.py +270 -0
- tescmd-0.2.0/tests/telemetry/__init__.py +0 -0
- tescmd-0.2.0/tests/telemetry/conftest.py +34 -0
- tescmd-0.2.0/tests/telemetry/test_dashboard.py +220 -0
- tescmd-0.2.0/tests/telemetry/test_decoder.py +280 -0
- tescmd-0.2.0/tests/telemetry/test_fields.py +73 -0
- tescmd-0.2.0/tests/telemetry/test_flatbuf.py +179 -0
- tescmd-0.2.0/tests/telemetry/test_server.py +219 -0
- tescmd-0.2.0/tests/telemetry/test_stream_cmd.py +42 -0
- tescmd-0.2.0/tests/telemetry/test_tailscale.py +289 -0
- tescmd-0.1.2/.claude/settings.local.json +0 -47
- tescmd-0.1.2/docs/plans/2025-01-29-mvp-design.md +0 -152
- tescmd-0.1.2/docs/plans/2025-01-29-mvp-implementation.md +0 -3073
- tescmd-0.1.2/docs/setup-enrollment-audit.md +0 -171
- tescmd-0.1.2/scripts/e2e_test.py +0 -307
- {tescmd-0.1.2 → tescmd-0.2.0}/.gitignore +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/LICENSE +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/docs/api-costs.md +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/docs/authentication.md +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/docs/vehicle-command-protocol.md +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/scripts/validate_fleet_api.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/spec/fleet_api_spec.json +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/__main__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/_internal/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/_internal/async_utils.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/_internal/permissions.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/_internal/vin.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/charging.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/command.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/energy.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/partner.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/sharing.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/signed_command.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/api/user.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/auth/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/auth/oauth.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/auth/server.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/auth/token_store.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/ble/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cache/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cache/keys.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/_client.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/_options.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/billing.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/cache.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/charge.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/climate.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/energy.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/media.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/nav.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/partner.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/raw.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/security.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/sharing.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/software.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/status.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/trunk.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/cli/user.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/config/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/crypto/keys.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/deploy/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/deploy/github_pages.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/command.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/sharing.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/user.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/models/vehicle.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/output/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/output/formatter.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/output/json_output.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/output/rich_output.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/commands.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/encoder.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/metadata.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/payloads.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/protobuf/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/protobuf/messages.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/protocol/signer.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/src/tescmd/py.typed +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/_internal/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/_internal/test_async_utils.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/_internal/test_vin.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_client.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_command_api.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_energy_api.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_partner_api.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_sharing_api.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_signed_command.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_user_api.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/api/test_vehicle_api.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_oauth.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_oauth_extended.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_server.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_token_store.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_token_store_fallback.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/auth/test_token_store_file.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cache/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cache/test_generic_cache.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cache/test_keys.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cache/test_response_cache.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/_helpers.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/conftest.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_auth.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_auth_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_cache.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_cached_api_call.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_charge_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_climate_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_energy.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_energy_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_error_handlers.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_key_enroll.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_key_unenroll.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_media.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_media_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_nav.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_nav_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_partner.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_raw.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_raw_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_security_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_setup_scope_check.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_sharing.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_sharing_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_software.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_software_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_status_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_tier_enforcement.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_trunk_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_user.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_user_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_vcsec_guard.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_vehicle_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_vehicle_power_exec.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_verbose.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/cli/test_wake_confirmation.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/conftest.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/crypto/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/crypto/test_ecdh.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/crypto/test_keys.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/deploy/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/deploy/test_github_pages.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_auth.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_config.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_energy.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_sharing.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_user_models.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/models/test_vehicle.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/output/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/output/test_formatter.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/output/test_json_output.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/output/test_rich_output.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/__init__.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/conftest.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/test_commands.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/test_encoder.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/test_metadata.py +0 -0
- {tescmd-0.1.2 → tescmd-0.2.0}/tests/protocol/test_session.py +0 -0
- {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
|
|
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,
|
|
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
|
-
│
|
|
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: ~
|
|
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.
|
|
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
|
-
|
|
51
|
-
|
|
53
|
+
[](https://pypi.org/project/tescmd/)
|
|
54
|
+
[](https://pypi.org/project/tescmd/)
|
|
55
|
+
[](https://github.com/oceanswave/tescmd/actions/workflows/test.yml)
|
|
52
56
|
[](LICENSE)
|
|
57
|
+
[](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
|
|
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
|
-
|
|
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
|
-
|
|
113
|
-
tescmd key enroll 5YJ3E1EA1NF000000
|
|
96
|
+
After setup completes, you can start using commands:
|
|
114
97
|
|
|
115
|
-
|
|
116
|
-
tescmd
|
|
117
|
-
tescmd
|
|
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 |
|
|
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
|
-
|
|
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
|
-
|
|
4
|
-
|
|
3
|
+
[](https://pypi.org/project/tescmd/)
|
|
4
|
+
[](https://pypi.org/project/tescmd/)
|
|
5
|
+
[](https://github.com/oceanswave/tescmd/actions/workflows/test.yml)
|
|
5
6
|
[](LICENSE)
|
|
7
|
+
[](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
|
|
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
|
-
|
|
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
|
-
|
|
66
|
-
tescmd key enroll 5YJ3E1EA1NF000000
|
|
46
|
+
After setup completes, you can start using commands:
|
|
67
47
|
|
|
68
|
-
|
|
69
|
-
tescmd
|
|
70
|
-
tescmd
|
|
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 |
|
|
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
|
-
|
|
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
|
|
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
|
|