pynissan 0.1.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.
- pynissan-0.1.0/CHANGELOG.md +75 -0
- pynissan-0.1.0/CONTRIBUTING.md +58 -0
- pynissan-0.1.0/LICENSE +21 -0
- pynissan-0.1.0/MANIFEST.in +5 -0
- pynissan-0.1.0/PKG-INFO +194 -0
- pynissan-0.1.0/README.md +157 -0
- pynissan-0.1.0/SECURITY.md +18 -0
- pynissan-0.1.0/docs/api.md +81 -0
- pynissan-0.1.0/docs/authentication.md +68 -0
- pynissan-0.1.0/docs/releasing.md +50 -0
- pynissan-0.1.0/pyproject.toml +93 -0
- pynissan-0.1.0/scripts/__init__.py +1 -0
- pynissan-0.1.0/scripts/check_file_size.py +52 -0
- pynissan-0.1.0/setup.cfg +4 -0
- pynissan-0.1.0/src/pynissan/__init__.py +1408 -0
- pynissan-0.1.0/src/pynissan/_account_client.py +321 -0
- pynissan-0.1.0/src/pynissan/_alert_client.py +457 -0
- pynissan-0.1.0/src/pynissan/_alert_models.py +125 -0
- pynissan-0.1.0/src/pynissan/_capability_models.py +90 -0
- pynissan-0.1.0/src/pynissan/_client_base.py +280 -0
- pynissan-0.1.0/src/pynissan/_client_helpers.py +148 -0
- pynissan-0.1.0/src/pynissan/_climate_charge_client.py +427 -0
- pynissan-0.1.0/src/pynissan/_commerce_catalog_parsing.py +139 -0
- pynissan-0.1.0/src/pynissan/_commerce_payment_parsing.py +191 -0
- pynissan-0.1.0/src/pynissan/_commerce_public_parsing.py +298 -0
- pynissan-0.1.0/src/pynissan/_commerce_value_parsing.py +104 -0
- pynissan-0.1.0/src/pynissan/_content_client.py +248 -0
- pynissan-0.1.0/src/pynissan/_core_models.py +184 -0
- pynissan-0.1.0/src/pynissan/_dealer_appointment_parsing.py +307 -0
- pynissan-0.1.0/src/pynissan/_dealer_client.py +381 -0
- pynissan-0.1.0/src/pynissan/_dealer_detail_parsing.py +212 -0
- pynissan-0.1.0/src/pynissan/_dealer_public_parsing.py +310 -0
- pynissan-0.1.0/src/pynissan/_dealer_value_parsing.py +110 -0
- pynissan-0.1.0/src/pynissan/_driver_client.py +198 -0
- pynissan-0.1.0/src/pynissan/_driver_detail_parsing.py +204 -0
- pynissan-0.1.0/src/pynissan/_driver_public_parsing.py +299 -0
- pynissan-0.1.0/src/pynissan/_driver_value_parsing.py +202 -0
- pynissan-0.1.0/src/pynissan/_energy_client.py +487 -0
- pynissan-0.1.0/src/pynissan/_energy_models.py +104 -0
- pynissan-0.1.0/src/pynissan/_extended_vehicle_driving_parsing.py +141 -0
- pynissan-0.1.0/src/pynissan/_extended_vehicle_location_parsing.py +298 -0
- pynissan-0.1.0/src/pynissan/_extended_vehicle_public_parsing.py +260 -0
- pynissan-0.1.0/src/pynissan/_extended_vehicle_tariff_parsing.py +250 -0
- pynissan-0.1.0/src/pynissan/_extended_vehicle_value_parsing.py +149 -0
- pynissan-0.1.0/src/pynissan/_finance_account_parsing.py +271 -0
- pynissan-0.1.0/src/pynissan/_finance_client.py +269 -0
- pynissan-0.1.0/src/pynissan/_finance_public_parsing.py +300 -0
- pynissan-0.1.0/src/pynissan/_finance_statement_parsing.py +282 -0
- pynissan-0.1.0/src/pynissan/_finance_value_parsing.py +88 -0
- pynissan-0.1.0/src/pynissan/_garage_client.py +312 -0
- pynissan-0.1.0/src/pynissan/_incident_client.py +179 -0
- pynissan-0.1.0/src/pynissan/_maintenance_detail_parsing.py +270 -0
- pynissan-0.1.0/src/pynissan/_maintenance_public_parsing.py +324 -0
- pynissan-0.1.0/src/pynissan/_maintenance_value_parsing.py +273 -0
- pynissan-0.1.0/src/pynissan/_message_client.py +112 -0
- pynissan-0.1.0/src/pynissan/_navigation_command_client.py +282 -0
- pynissan-0.1.0/src/pynissan/_navigation_public_parsing.py +370 -0
- pynissan-0.1.0/src/pynissan/_navigation_read_client.py +202 -0
- pynissan-0.1.0/src/pynissan/_navigation_value_parsing.py +114 -0
- pynissan-0.1.0/src/pynissan/_navigation_waypoint_parsing.py +273 -0
- pynissan-0.1.0/src/pynissan/_ota_notification_client.py +281 -0
- pynissan-0.1.0/src/pynissan/_parsing_values.py +230 -0
- pynissan-0.1.0/src/pynissan/_polling_client.py +103 -0
- pynissan-0.1.0/src/pynissan/_profile.py +84 -0
- pynissan-0.1.0/src/pynissan/_request_models.py +115 -0
- pynissan-0.1.0/src/pynissan/_second_delivery_client.py +227 -0
- pynissan-0.1.0/src/pynissan/_second_delivery_detail_parsing.py +412 -0
- pynissan-0.1.0/src/pynissan/_second_delivery_public_parsing.py +213 -0
- pynissan-0.1.0/src/pynissan/_second_delivery_value_parsing.py +77 -0
- pynissan-0.1.0/src/pynissan/_transport.py +483 -0
- pynissan-0.1.0/src/pynissan/_vehicle_alert_parsing.py +231 -0
- pynissan-0.1.0/src/pynissan/_vehicle_capability_parsing.py +161 -0
- pynissan-0.1.0/src/pynissan/_vehicle_command_client.py +293 -0
- pynissan-0.1.0/src/pynissan/_vehicle_core_parsing.py +312 -0
- pynissan-0.1.0/src/pynissan/_vehicle_data_client.py +315 -0
- pynissan-0.1.0/src/pynissan/_vehicle_detail_client.py +233 -0
- pynissan-0.1.0/src/pynissan/_vehicle_energy_parsing.py +196 -0
- pynissan-0.1.0/src/pynissan/_vehicle_models.py +141 -0
- pynissan-0.1.0/src/pynissan/_vehicle_response_parsing.py +235 -0
- pynissan-0.1.0/src/pynissan/_vehicle_status_models.py +135 -0
- pynissan-0.1.0/src/pynissan/_vehicle_subscription_parsing.py +253 -0
- pynissan-0.1.0/src/pynissan/_version.py +3 -0
- pynissan-0.1.0/src/pynissan/account_enrollment_parsing.py +343 -0
- pynissan-0.1.0/src/pynissan/account_inputs.py +287 -0
- pynissan-0.1.0/src/pynissan/account_models.py +526 -0
- pynissan-0.1.0/src/pynissan/account_parsing.py +508 -0
- pynissan-0.1.0/src/pynissan/alert_inputs.py +186 -0
- pynissan-0.1.0/src/pynissan/callbacks.py +13 -0
- pynissan-0.1.0/src/pynissan/charge_plan_inputs.py +37 -0
- pynissan-0.1.0/src/pynissan/charge_plan_models.py +107 -0
- pynissan-0.1.0/src/pynissan/charge_plan_parsing.py +237 -0
- pynissan-0.1.0/src/pynissan/client.py +43 -0
- pynissan-0.1.0/src/pynissan/collision_report_inputs.py +286 -0
- pynissan-0.1.0/src/pynissan/collision_report_models.py +150 -0
- pynissan-0.1.0/src/pynissan/collision_report_parsing.py +279 -0
- pynissan-0.1.0/src/pynissan/commerce_inputs.py +85 -0
- pynissan-0.1.0/src/pynissan/commerce_models.py +307 -0
- pynissan-0.1.0/src/pynissan/commerce_parsing.py +27 -0
- pynissan-0.1.0/src/pynissan/common_inputs.py +46 -0
- pynissan-0.1.0/src/pynissan/content_inputs.py +32 -0
- pynissan-0.1.0/src/pynissan/content_models.py +128 -0
- pynissan-0.1.0/src/pynissan/content_parsing.py +289 -0
- pynissan-0.1.0/src/pynissan/countries.py +7 -0
- pynissan-0.1.0/src/pynissan/dealer_inputs.py +373 -0
- pynissan-0.1.0/src/pynissan/dealer_models.py +357 -0
- pynissan-0.1.0/src/pynissan/dealer_parsing.py +39 -0
- pynissan-0.1.0/src/pynissan/device_notification_inputs.py +124 -0
- pynissan-0.1.0/src/pynissan/device_notification_models.py +60 -0
- pynissan-0.1.0/src/pynissan/device_notification_parsing.py +209 -0
- pynissan-0.1.0/src/pynissan/driver_inputs.py +251 -0
- pynissan-0.1.0/src/pynissan/driver_models.py +232 -0
- pynissan-0.1.0/src/pynissan/driver_parsing.py +29 -0
- pynissan-0.1.0/src/pynissan/energy_account_models.py +105 -0
- pynissan-0.1.0/src/pynissan/energy_account_parsing.py +160 -0
- pynissan-0.1.0/src/pynissan/exceptions.py +41 -0
- pynissan-0.1.0/src/pynissan/extended_vehicle_inputs.py +147 -0
- pynissan-0.1.0/src/pynissan/extended_vehicle_models.py +418 -0
- pynissan-0.1.0/src/pynissan/extended_vehicle_parsing.py +23 -0
- pynissan-0.1.0/src/pynissan/finance_inputs.py +138 -0
- pynissan-0.1.0/src/pynissan/finance_models.py +422 -0
- pynissan-0.1.0/src/pynissan/finance_parsing.py +37 -0
- pynissan-0.1.0/src/pynissan/garage_inputs.py +202 -0
- pynissan-0.1.0/src/pynissan/garage_models.py +311 -0
- pynissan-0.1.0/src/pynissan/garage_parsing.py +513 -0
- pynissan-0.1.0/src/pynissan/graphql_input.py +36 -0
- pynissan-0.1.0/src/pynissan/insurance_inputs.py +32 -0
- pynissan-0.1.0/src/pynissan/insurance_models.py +66 -0
- pynissan-0.1.0/src/pynissan/insurance_parsing.py +169 -0
- pynissan-0.1.0/src/pynissan/maintenance_inputs.py +275 -0
- pynissan-0.1.0/src/pynissan/maintenance_models.py +182 -0
- pynissan-0.1.0/src/pynissan/maintenance_parsing.py +29 -0
- pynissan-0.1.0/src/pynissan/models.py +239 -0
- pynissan-0.1.0/src/pynissan/navigation_inputs.py +392 -0
- pynissan-0.1.0/src/pynissan/navigation_models.py +321 -0
- pynissan-0.1.0/src/pynissan/navigation_parsing.py +19 -0
- pynissan-0.1.0/src/pynissan/notification_inputs.py +82 -0
- pynissan-0.1.0/src/pynissan/notification_models.py +100 -0
- pynissan-0.1.0/src/pynissan/notification_parsing.py +214 -0
- pynissan-0.1.0/src/pynissan/operations.py +1522 -0
- pynissan-0.1.0/src/pynissan/ota_inputs.py +30 -0
- pynissan-0.1.0/src/pynissan/ota_models.py +90 -0
- pynissan-0.1.0/src/pynissan/ota_parsing.py +214 -0
- pynissan-0.1.0/src/pynissan/parsing.py +65 -0
- pynissan-0.1.0/src/pynissan/pnc_inputs.py +49 -0
- pynissan-0.1.0/src/pynissan/pnc_models.py +199 -0
- pynissan-0.1.0/src/pynissan/pnc_parsing.py +276 -0
- pynissan-0.1.0/src/pynissan/py.typed +1 -0
- pynissan-0.1.0/src/pynissan/request_proof.py +13 -0
- pynissan-0.1.0/src/pynissan/second_delivery_inputs.py +157 -0
- pynissan-0.1.0/src/pynissan/second_delivery_models.py +292 -0
- pynissan-0.1.0/src/pynissan/second_delivery_parsing.py +29 -0
- pynissan-0.1.0/src/pynissan/service_inputs.py +48 -0
- pynissan-0.1.0/src/pynissan/service_models.py +153 -0
- pynissan-0.1.0/src/pynissan/service_parsing.py +531 -0
- pynissan-0.1.0/src/pynissan/v1g_inputs.py +104 -0
- pynissan-0.1.0/src/pynissan/v1g_models.py +108 -0
- pynissan-0.1.0/src/pynissan/v1g_parsing.py +282 -0
- pynissan-0.1.0/src/pynissan/vehicle_detail_inputs.py +114 -0
- pynissan-0.1.0/src/pynissan/vehicle_detail_models.py +31 -0
- pynissan-0.1.0/src/pynissan/vehicle_detail_parsing.py +177 -0
- pynissan-0.1.0/src/pynissan/wearable_models.py +27 -0
- pynissan-0.1.0/src/pynissan/wearable_parsing.py +127 -0
- pynissan-0.1.0/src/pynissan.egg-info/PKG-INFO +194 -0
- pynissan-0.1.0/src/pynissan.egg-info/SOURCES.txt +225 -0
- pynissan-0.1.0/src/pynissan.egg-info/dependency_links.txt +1 -0
- pynissan-0.1.0/src/pynissan.egg-info/requires.txt +10 -0
- pynissan-0.1.0/src/pynissan.egg-info/top_level.txt +1 -0
- pynissan-0.1.0/tests/test_account_inputs_and_queries.py +309 -0
- pynissan-0.1.0/tests/test_account_mutations.py +442 -0
- pynissan-0.1.0/tests/test_account_vehicle_client.py +491 -0
- pynissan-0.1.0/tests/test_charge_plans.py +493 -0
- pynissan-0.1.0/tests/test_client.py +118 -0
- pynissan-0.1.0/tests/test_client_part_01.py +336 -0
- pynissan-0.1.0/tests/test_client_part_02.py +313 -0
- pynissan-0.1.0/tests/test_client_part_03.py +313 -0
- pynissan-0.1.0/tests/test_client_part_04.py +336 -0
- pynissan-0.1.0/tests/test_client_part_05.py +318 -0
- pynissan-0.1.0/tests/test_client_part_06.py +340 -0
- pynissan-0.1.0/tests/test_client_part_07.py +270 -0
- pynissan-0.1.0/tests/test_client_part_08.py +314 -0
- pynissan-0.1.0/tests/test_client_part_09.py +335 -0
- pynissan-0.1.0/tests/test_client_part_10.py +334 -0
- pynissan-0.1.0/tests/test_client_part_11.py +274 -0
- pynissan-0.1.0/tests/test_client_part_12.py +283 -0
- pynissan-0.1.0/tests/test_client_part_13.py +333 -0
- pynissan-0.1.0/tests/test_client_part_14.py +328 -0
- pynissan-0.1.0/tests/test_client_part_15.py +197 -0
- pynissan-0.1.0/tests/test_commerce.py +81 -0
- pynissan-0.1.0/tests/test_commerce_part_01.py +312 -0
- pynissan-0.1.0/tests/test_commerce_part_02.py +216 -0
- pynissan-0.1.0/tests/test_content_and_support.py +271 -0
- pynissan-0.1.0/tests/test_dealers_and_service_appointments.py +416 -0
- pynissan-0.1.0/tests/test_device_notifications.py +521 -0
- pynissan-0.1.0/tests/test_drivers.py +88 -0
- pynissan-0.1.0/tests/test_drivers_part_01.py +347 -0
- pynissan-0.1.0/tests/test_drivers_part_02.py +280 -0
- pynissan-0.1.0/tests/test_drivers_part_03.py +115 -0
- pynissan-0.1.0/tests/test_energy_account.py +378 -0
- pynissan-0.1.0/tests/test_energy_client.py +209 -0
- pynissan-0.1.0/tests/test_energy_notifications.py +253 -0
- pynissan-0.1.0/tests/test_extended_vehicle_reads.py +83 -0
- pynissan-0.1.0/tests/test_extended_vehicle_reads_part_01.py +308 -0
- pynissan-0.1.0/tests/test_extended_vehicle_reads_part_02.py +277 -0
- pynissan-0.1.0/tests/test_extended_vehicle_reads_part_03.py +266 -0
- pynissan-0.1.0/tests/test_extended_vehicle_reads_part_04.py +176 -0
- pynissan-0.1.0/tests/test_finance.py +370 -0
- pynissan-0.1.0/tests/test_garage.py +93 -0
- pynissan-0.1.0/tests/test_garage_part_01.py +374 -0
- pynissan-0.1.0/tests/test_garage_part_02.py +338 -0
- pynissan-0.1.0/tests/test_garage_part_03.py +214 -0
- pynissan-0.1.0/tests/test_insurance_and_collision_reports.py +417 -0
- pynissan-0.1.0/tests/test_maintenance.py +124 -0
- pynissan-0.1.0/tests/test_maintenance_part_01.py +368 -0
- pynissan-0.1.0/tests/test_maintenance_part_02.py +317 -0
- pynissan-0.1.0/tests/test_operation_catalog.py +19 -0
- pynissan-0.1.0/tests/test_pnc.py +82 -0
- pynissan-0.1.0/tests/test_pnc_part_01.py +310 -0
- pynissan-0.1.0/tests/test_pnc_part_02.py +309 -0
- pynissan-0.1.0/tests/test_public_api.py +37 -0
- pynissan-0.1.0/tests/test_safety_contracts.py +84 -0
- pynissan-0.1.0/tests/test_second_delivery.py +412 -0
- pynissan-0.1.0/tests/test_service_reads.py +196 -0
- pynissan-0.1.0/tests/test_service_reads_part_01.py +324 -0
- pynissan-0.1.0/tests/test_service_reads_part_02.py +113 -0
- pynissan-0.1.0/tests/test_v1g.py +460 -0
- pynissan-0.1.0/tests/test_vehicle_detail_reads.py +334 -0
- pynissan-0.1.0/tests/test_wearable_vehicles.py +311 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `pynissan` are documented in this file.
|
|
4
|
+
|
|
5
|
+
The project follows [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
<!-- version list -->
|
|
8
|
+
|
|
9
|
+
## v0.1.0 (2026-08-01)
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- Harden command status and enum inputs
|
|
14
|
+
([`415326b`](https://github.com/bvdcode/nissan-connect-sdk/commit/415326b528332d6c835c9a6a3ea6743a39d15dd4))
|
|
15
|
+
|
|
16
|
+
- Surface polling timeouts consistently
|
|
17
|
+
([`527172e`](https://github.com/bvdcode/nissan-connect-sdk/commit/527172ee532c4d7955ba2d3cbe7b44540962ea66))
|
|
18
|
+
|
|
19
|
+
### Continuous Integration
|
|
20
|
+
|
|
21
|
+
- Automate semantic releases
|
|
22
|
+
([`f2bb388`](https://github.com/bvdcode/nissan-connect-sdk/commit/f2bb38822fe8aaba230e441a4201ba74898c421a))
|
|
23
|
+
|
|
24
|
+
- Automate tagged releases
|
|
25
|
+
([`2d63335`](https://github.com/bvdcode/nissan-connect-sdk/commit/2d6333561aa02ee60744d03dce4e3673722855c9))
|
|
26
|
+
|
|
27
|
+
- Automate validation and PyPI publishing
|
|
28
|
+
([`697274a`](https://github.com/bvdcode/nissan-connect-sdk/commit/697274aeb91d95da5e39bc529bec8a479efcd99a))
|
|
29
|
+
|
|
30
|
+
- Enforce Python module size limit
|
|
31
|
+
([`5192435`](https://github.com/bvdcode/nissan-connect-sdk/commit/5192435c10fdb132f474842c260b3b03bd63053f))
|
|
32
|
+
|
|
33
|
+
- Install release build tooling
|
|
34
|
+
([`c5cf9c2`](https://github.com/bvdcode/nissan-connect-sdk/commit/c5cf9c26dd637f170897d95e1d7bc5affbf7b792))
|
|
35
|
+
|
|
36
|
+
### Documentation
|
|
37
|
+
|
|
38
|
+
- Describe protected request configuration
|
|
39
|
+
([`f304cf8`](https://github.com/bvdcode/nissan-connect-sdk/commit/f304cf84e596a22bbd35dcb977e41dc7cc9937c2))
|
|
40
|
+
|
|
41
|
+
- Prepare the package for release
|
|
42
|
+
([`1087b74`](https://github.com/bvdcode/nissan-connect-sdk/commit/1087b74f2563a90b98c3f9103b881637cc8c7d8b))
|
|
43
|
+
|
|
44
|
+
### Features
|
|
45
|
+
|
|
46
|
+
- Add the pynissan async client
|
|
47
|
+
([`21f8dbc`](https://github.com/bvdcode/nissan-connect-sdk/commit/21f8dbcd439c68afa1e72c4ae8b889fddccd22cb))
|
|
48
|
+
|
|
49
|
+
- Support protected onboarding requests
|
|
50
|
+
([`c68dce3`](https://github.com/bvdcode/nissan-connect-sdk/commit/c68dce32dfa741c34144da1631d967808f1e95e3))
|
|
51
|
+
|
|
52
|
+
### Refactoring
|
|
53
|
+
|
|
54
|
+
- Keep transport internals private
|
|
55
|
+
([`92e4c9c`](https://github.com/bvdcode/nissan-connect-sdk/commit/92e4c9cf5b0bff599091edc87bc4a6f5f59a47f0))
|
|
56
|
+
|
|
57
|
+
- Split account feature parsers
|
|
58
|
+
([`397dd50`](https://github.com/bvdcode/nissan-connect-sdk/commit/397dd505b9fe2931a56a42242842ff430aac946c))
|
|
59
|
+
|
|
60
|
+
- Split client by service domain
|
|
61
|
+
([`26d71a4`](https://github.com/bvdcode/nissan-connect-sdk/commit/26d71a414c597b833626740b2357230f13ded855))
|
|
62
|
+
|
|
63
|
+
- Split core domain models
|
|
64
|
+
([`1df47fb`](https://github.com/bvdcode/nissan-connect-sdk/commit/1df47fb07f5eea54b07ff8aaa99964020cedb6e7))
|
|
65
|
+
|
|
66
|
+
- Split oversized test modules
|
|
67
|
+
([`50247a8`](https://github.com/bvdcode/nissan-connect-sdk/commit/50247a8368d2a884443f37bf0cb84153864d1d67))
|
|
68
|
+
|
|
69
|
+
- Split vehicle service parsers
|
|
70
|
+
([`9408521`](https://github.com/bvdcode/nissan-connect-sdk/commit/9408521515e8e225f9864eb5ec7dc05640f53a1c))
|
|
71
|
+
|
|
72
|
+
### Testing
|
|
73
|
+
|
|
74
|
+
- Cover connected vehicle operations
|
|
75
|
+
([`6129b49`](https://github.com/bvdcode/nissan-connect-sdk/commit/6129b49a1b451eae5bddf42c9761b3fdbd08b275))
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Contributions that improve correctness, type safety, test coverage, or supported vehicle
|
|
4
|
+
features are welcome.
|
|
5
|
+
|
|
6
|
+
## Development setup
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
python -m venv .venv
|
|
10
|
+
python -m pip install -e ".[test]"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run the complete quality gate before opening a pull request:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
python -m ruff check .
|
|
17
|
+
python -m ruff format --check .
|
|
18
|
+
python -m mypy
|
|
19
|
+
python scripts/check_file_size.py
|
|
20
|
+
python -m pytest
|
|
21
|
+
python -m build
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Code guidelines
|
|
25
|
+
|
|
26
|
+
- Add precise type hints to all new functions, methods, and attributes.
|
|
27
|
+
- Add concise English docstrings to public classes, functions, and methods.
|
|
28
|
+
- Keep request serialization, transport, response parsing, and domain models separate.
|
|
29
|
+
- Preserve nullable fields and unknown upstream values instead of inventing defaults.
|
|
30
|
+
- Add focused tests for request variables, response parsing, errors, and read-only behavior.
|
|
31
|
+
- Keep state-changing operations behind the client's read-only guard.
|
|
32
|
+
- Keep handwritten Python files at or below 500 non-empty, non-comment lines. Prefer
|
|
33
|
+
300–400 lines and split by responsibility before reaching the hard limit.
|
|
34
|
+
|
|
35
|
+
The only size-limit exceptions are the public export barrel in `src/pynissan/__init__.py`
|
|
36
|
+
and the declarative GraphQL document catalog in `src/pynissan/operations.py`.
|
|
37
|
+
|
|
38
|
+
## Test data
|
|
39
|
+
|
|
40
|
+
Use neutral fixtures. Never commit credentials, OAuth tokens, vehicle identifiers, account
|
|
41
|
+
details, private URLs, or captured customer responses.
|
|
42
|
+
|
|
43
|
+
## Pull requests
|
|
44
|
+
|
|
45
|
+
Keep each pull request focused and describe the product behavior it changes. Include tests for
|
|
46
|
+
new behavior and note any vehicle capability required to exercise it.
|
|
47
|
+
|
|
48
|
+
Pull requests are squash merged. Use a Conventional Commit title because the resulting merge
|
|
49
|
+
commit controls versioning and becomes the release-note entry:
|
|
50
|
+
|
|
51
|
+
- `feat:` for a new public capability and a minor release.
|
|
52
|
+
- `fix:` or `perf:` for a patch release.
|
|
53
|
+
- `BREAKING CHANGE:` in the body for a major release.
|
|
54
|
+
- `build:`, `chore:`, `ci:`, `docs:`, `refactor:`, `style:`, or `test:` for changes that do not
|
|
55
|
+
release by themselves.
|
|
56
|
+
|
|
57
|
+
Do not edit the project version or create version tags manually. The release workflow updates the
|
|
58
|
+
version and changelog after a releasable commit reaches `main`.
|
pynissan-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vadim Belov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pynissan-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pynissan
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Independent async Python client for MyNISSAN connected vehicles
|
|
5
|
+
Author: Vadim Belov
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Changelog, https://github.com/bvdcode/nissan-connect-sdk/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: Documentation, https://github.com/bvdcode/nissan-connect-sdk/tree/main/docs
|
|
9
|
+
Project-URL: Issues, https://github.com/bvdcode/nissan-connect-sdk/issues
|
|
10
|
+
Project-URL: Repository, https://github.com/bvdcode/nissan-connect-sdk
|
|
11
|
+
Keywords: ariya,asyncio,connected-car,home-assistant,nissan
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Framework :: AsyncIO
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: Home Automation
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: aiohttp<4,>=3.12
|
|
28
|
+
Provides-Extra: test
|
|
29
|
+
Requires-Dist: build<2,>=1.5; extra == "test"
|
|
30
|
+
Requires-Dist: mypy<3,>=2.3; extra == "test"
|
|
31
|
+
Requires-Dist: python-semantic-release<11,>=10.6; extra == "test"
|
|
32
|
+
Requires-Dist: pytest<10,>=9.1; extra == "test"
|
|
33
|
+
Requires-Dist: pytest-asyncio<2,>=1.4; extra == "test"
|
|
34
|
+
Requires-Dist: ruff<0.17,>=0.16; extra == "test"
|
|
35
|
+
Requires-Dist: twine<7,>=6.2; extra == "test"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# pynissan
|
|
39
|
+
|
|
40
|
+
[](https://github.com/bvdcode/nissan-connect-sdk/actions/workflows/ci.yml)
|
|
41
|
+
[](https://pypi.org/project/pynissan/)
|
|
42
|
+
[](https://pypi.org/project/pynissan/)
|
|
43
|
+
[](LICENSE)
|
|
44
|
+
|
|
45
|
+
`pynissan` is an independently maintained async Python client for MyNISSAN connected
|
|
46
|
+
vehicle services. It provides a typed API for vehicle telemetry, charging, climate,
|
|
47
|
+
remote commands, account data, and connected-service features.
|
|
48
|
+
|
|
49
|
+
The client currently supports United States MyNISSAN accounts and includes Nissan Ariya
|
|
50
|
+
telemetry and remote-control support.
|
|
51
|
+
|
|
52
|
+
## Highlights
|
|
53
|
+
|
|
54
|
+
- Fully async I/O built on `aiohttp`.
|
|
55
|
+
- Typed, immutable response models and a `py.typed` marker.
|
|
56
|
+
- Cached vehicle, battery, charging, climate, door, location, tire, and mileage data.
|
|
57
|
+
- Charging, climate, lock, light, horn, engine, location, and status-refresh commands.
|
|
58
|
+
- Climate and charge schedules, vehicle capabilities, alerts, maintenance, and history.
|
|
59
|
+
- Automatic access-token refresh with a callback for persisting replacement tokens.
|
|
60
|
+
- Static or refreshable request proof for protected service operations.
|
|
61
|
+
- Read-only mode enabled by default for safe discovery and monitoring.
|
|
62
|
+
- No dependency on Home Assistant.
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
python -m pip install pynissan
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Python 3.12 or newer is required.
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
The caller owns the `aiohttp.ClientSession` and decides how credentials and reusable tokens
|
|
75
|
+
are stored.
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from aiohttp import ClientSession
|
|
79
|
+
|
|
80
|
+
from pynissan import Country, NissanClient, Tokens
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
async def save_tokens(tokens: Tokens) -> None:
|
|
84
|
+
"""Persist replacement tokens in the application's secure storage."""
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
async def read_vehicle(email: str, password: str) -> None:
|
|
88
|
+
async with ClientSession() as session:
|
|
89
|
+
client = NissanClient(
|
|
90
|
+
session,
|
|
91
|
+
country=Country.US,
|
|
92
|
+
token_listener=save_tokens,
|
|
93
|
+
)
|
|
94
|
+
await client.async_authenticate(email, password)
|
|
95
|
+
|
|
96
|
+
vehicles = await client.async_get_vehicles()
|
|
97
|
+
if not vehicles:
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
status = await client.async_get_vehicle_status(vehicles[0].vin)
|
|
101
|
+
if status.battery is not None:
|
|
102
|
+
print(status.battery.level)
|
|
103
|
+
print(status.battery.is_charging)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Supply previously saved tokens to avoid signing in again:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
client = NissanClient(
|
|
110
|
+
session,
|
|
111
|
+
country=Country.US,
|
|
112
|
+
tokens=saved_tokens,
|
|
113
|
+
token_listener=save_tokens,
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The client refreshes expired tokens before a request and publishes the replacement token set
|
|
118
|
+
through `token_listener`.
|
|
119
|
+
|
|
120
|
+
Protected operations accept a `RequestProof` value or an async `RequestProofProvider`. The
|
|
121
|
+
provider is called with `False` for a current value and with `True` when the service rejects a
|
|
122
|
+
stale value.
|
|
123
|
+
|
|
124
|
+
## Read-only safety
|
|
125
|
+
|
|
126
|
+
`NissanClient` starts in read-only mode. Queries work normally, while methods that change
|
|
127
|
+
vehicle or account state raise `ReadOnlyError` before any network request is sent.
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from pynissan import Country, NissanClient
|
|
131
|
+
|
|
132
|
+
client = NissanClient(
|
|
133
|
+
session,
|
|
134
|
+
country=Country.US,
|
|
135
|
+
tokens=saved_tokens,
|
|
136
|
+
read_only=False,
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Enable write access only for an explicit user action. Remote commands return a typed request
|
|
141
|
+
that can be polled until Nissan reports a terminal status.
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from pynissan import ClimateSettings, TemperatureUnit
|
|
145
|
+
|
|
146
|
+
request = await client.async_start_climate(
|
|
147
|
+
vin,
|
|
148
|
+
ClimateSettings(72, TemperatureUnit.FAHRENHEIT),
|
|
149
|
+
)
|
|
150
|
+
result = await client.async_wait_for_service_request(vin, request)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Charging state
|
|
154
|
+
|
|
155
|
+
Battery status distinguishes the cable and charging states and includes the server-provided
|
|
156
|
+
remaining charge time.
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
battery = await client.async_get_vehicle_battery_status(vin)
|
|
160
|
+
if battery is not None:
|
|
161
|
+
print(battery.level)
|
|
162
|
+
print(battery.is_plugged_in)
|
|
163
|
+
print(battery.is_charging)
|
|
164
|
+
print(battery.remaining_charge_time)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Errors
|
|
168
|
+
|
|
169
|
+
All package exceptions inherit from `NissanError`:
|
|
170
|
+
|
|
171
|
+
- `AuthenticationError` for sign-in and token-refresh failures;
|
|
172
|
+
- `NetworkError` for connection and timeout failures;
|
|
173
|
+
- `ApiError` for rejected HTTP requests;
|
|
174
|
+
- `GraphQLError` for rejected GraphQL operations;
|
|
175
|
+
- `ResponseError` for malformed responses;
|
|
176
|
+
- `ReadOnlyError` for blocked state-changing operations.
|
|
177
|
+
|
|
178
|
+
## Development
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
python -m pip install -e ".[test]"
|
|
182
|
+
python -m ruff check .
|
|
183
|
+
python -m ruff format --check .
|
|
184
|
+
python -m mypy
|
|
185
|
+
python -m pytest
|
|
186
|
+
python -m build
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
See the [API guide](docs/api.md) and [authentication guide](docs/authentication.md) for usage
|
|
190
|
+
details. Development and release procedures are documented in
|
|
191
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) and [docs/releasing.md](docs/releasing.md). Security issues
|
|
192
|
+
should follow [SECURITY.md](SECURITY.md).
|
|
193
|
+
|
|
194
|
+
`pynissan` is an independent community project and is not affiliated with Nissan.
|
pynissan-0.1.0/README.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# pynissan
|
|
2
|
+
|
|
3
|
+
[](https://github.com/bvdcode/nissan-connect-sdk/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/pynissan/)
|
|
5
|
+
[](https://pypi.org/project/pynissan/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
`pynissan` is an independently maintained async Python client for MyNISSAN connected
|
|
9
|
+
vehicle services. It provides a typed API for vehicle telemetry, charging, climate,
|
|
10
|
+
remote commands, account data, and connected-service features.
|
|
11
|
+
|
|
12
|
+
The client currently supports United States MyNISSAN accounts and includes Nissan Ariya
|
|
13
|
+
telemetry and remote-control support.
|
|
14
|
+
|
|
15
|
+
## Highlights
|
|
16
|
+
|
|
17
|
+
- Fully async I/O built on `aiohttp`.
|
|
18
|
+
- Typed, immutable response models and a `py.typed` marker.
|
|
19
|
+
- Cached vehicle, battery, charging, climate, door, location, tire, and mileage data.
|
|
20
|
+
- Charging, climate, lock, light, horn, engine, location, and status-refresh commands.
|
|
21
|
+
- Climate and charge schedules, vehicle capabilities, alerts, maintenance, and history.
|
|
22
|
+
- Automatic access-token refresh with a callback for persisting replacement tokens.
|
|
23
|
+
- Static or refreshable request proof for protected service operations.
|
|
24
|
+
- Read-only mode enabled by default for safe discovery and monitoring.
|
|
25
|
+
- No dependency on Home Assistant.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
python -m pip install pynissan
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Python 3.12 or newer is required.
|
|
34
|
+
|
|
35
|
+
## Quick start
|
|
36
|
+
|
|
37
|
+
The caller owns the `aiohttp.ClientSession` and decides how credentials and reusable tokens
|
|
38
|
+
are stored.
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from aiohttp import ClientSession
|
|
42
|
+
|
|
43
|
+
from pynissan import Country, NissanClient, Tokens
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def save_tokens(tokens: Tokens) -> None:
|
|
47
|
+
"""Persist replacement tokens in the application's secure storage."""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def read_vehicle(email: str, password: str) -> None:
|
|
51
|
+
async with ClientSession() as session:
|
|
52
|
+
client = NissanClient(
|
|
53
|
+
session,
|
|
54
|
+
country=Country.US,
|
|
55
|
+
token_listener=save_tokens,
|
|
56
|
+
)
|
|
57
|
+
await client.async_authenticate(email, password)
|
|
58
|
+
|
|
59
|
+
vehicles = await client.async_get_vehicles()
|
|
60
|
+
if not vehicles:
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
status = await client.async_get_vehicle_status(vehicles[0].vin)
|
|
64
|
+
if status.battery is not None:
|
|
65
|
+
print(status.battery.level)
|
|
66
|
+
print(status.battery.is_charging)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Supply previously saved tokens to avoid signing in again:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
client = NissanClient(
|
|
73
|
+
session,
|
|
74
|
+
country=Country.US,
|
|
75
|
+
tokens=saved_tokens,
|
|
76
|
+
token_listener=save_tokens,
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The client refreshes expired tokens before a request and publishes the replacement token set
|
|
81
|
+
through `token_listener`.
|
|
82
|
+
|
|
83
|
+
Protected operations accept a `RequestProof` value or an async `RequestProofProvider`. The
|
|
84
|
+
provider is called with `False` for a current value and with `True` when the service rejects a
|
|
85
|
+
stale value.
|
|
86
|
+
|
|
87
|
+
## Read-only safety
|
|
88
|
+
|
|
89
|
+
`NissanClient` starts in read-only mode. Queries work normally, while methods that change
|
|
90
|
+
vehicle or account state raise `ReadOnlyError` before any network request is sent.
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from pynissan import Country, NissanClient
|
|
94
|
+
|
|
95
|
+
client = NissanClient(
|
|
96
|
+
session,
|
|
97
|
+
country=Country.US,
|
|
98
|
+
tokens=saved_tokens,
|
|
99
|
+
read_only=False,
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Enable write access only for an explicit user action. Remote commands return a typed request
|
|
104
|
+
that can be polled until Nissan reports a terminal status.
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from pynissan import ClimateSettings, TemperatureUnit
|
|
108
|
+
|
|
109
|
+
request = await client.async_start_climate(
|
|
110
|
+
vin,
|
|
111
|
+
ClimateSettings(72, TemperatureUnit.FAHRENHEIT),
|
|
112
|
+
)
|
|
113
|
+
result = await client.async_wait_for_service_request(vin, request)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Charging state
|
|
117
|
+
|
|
118
|
+
Battery status distinguishes the cable and charging states and includes the server-provided
|
|
119
|
+
remaining charge time.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
battery = await client.async_get_vehicle_battery_status(vin)
|
|
123
|
+
if battery is not None:
|
|
124
|
+
print(battery.level)
|
|
125
|
+
print(battery.is_plugged_in)
|
|
126
|
+
print(battery.is_charging)
|
|
127
|
+
print(battery.remaining_charge_time)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Errors
|
|
131
|
+
|
|
132
|
+
All package exceptions inherit from `NissanError`:
|
|
133
|
+
|
|
134
|
+
- `AuthenticationError` for sign-in and token-refresh failures;
|
|
135
|
+
- `NetworkError` for connection and timeout failures;
|
|
136
|
+
- `ApiError` for rejected HTTP requests;
|
|
137
|
+
- `GraphQLError` for rejected GraphQL operations;
|
|
138
|
+
- `ResponseError` for malformed responses;
|
|
139
|
+
- `ReadOnlyError` for blocked state-changing operations.
|
|
140
|
+
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
python -m pip install -e ".[test]"
|
|
145
|
+
python -m ruff check .
|
|
146
|
+
python -m ruff format --check .
|
|
147
|
+
python -m mypy
|
|
148
|
+
python -m pytest
|
|
149
|
+
python -m build
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
See the [API guide](docs/api.md) and [authentication guide](docs/authentication.md) for usage
|
|
153
|
+
details. Development and release procedures are documented in
|
|
154
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) and [docs/releasing.md](docs/releasing.md). Security issues
|
|
155
|
+
should follow [SECURITY.md](SECURITY.md).
|
|
156
|
+
|
|
157
|
+
`pynissan` is an independent community project and is not affiliated with Nissan.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Report package vulnerabilities through
|
|
6
|
+
[GitHub private vulnerability reporting](https://github.com/bvdcode/nissan-connect-sdk/security/advisories/new).
|
|
7
|
+
Do not open a public issue for a vulnerability that could expose account or vehicle access.
|
|
8
|
+
|
|
9
|
+
Include the affected version, impact, reproduction steps, and a minimal test case when
|
|
10
|
+
available. Do not include credentials, OAuth tokens, vehicle identifiers, or customer data.
|
|
11
|
+
|
|
12
|
+
## Supported versions
|
|
13
|
+
|
|
14
|
+
Security fixes are released for the latest minor version of `pynissan`.
|
|
15
|
+
|
|
16
|
+
| Version | Supported |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| 0.1.x | Yes |
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# API guide
|
|
2
|
+
|
|
3
|
+
The package exports `NissanClient`, `Country`, `Tokens`, `RequestProof`,
|
|
4
|
+
`RequestProofProvider`, domain models, input models, enums, and exceptions from the
|
|
5
|
+
`pynissan` namespace. Public objects include precise type hints and runtime docstrings.
|
|
6
|
+
|
|
7
|
+
## Client lifecycle
|
|
8
|
+
|
|
9
|
+
The caller owns the `aiohttp.ClientSession` and closes it after all client work is complete.
|
|
10
|
+
One client represents one account and one country.
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from aiohttp import ClientSession
|
|
14
|
+
|
|
15
|
+
from pynissan import Country, NissanClient
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async with ClientSession() as session:
|
|
19
|
+
client = NissanClient(session, country=Country.US)
|
|
20
|
+
await client.async_authenticate(email, password)
|
|
21
|
+
vehicles = await client.async_get_vehicles()
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Common reads
|
|
25
|
+
|
|
26
|
+
| Method | Result |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| `async_get_vehicles()` | Vehicles associated with the account |
|
|
29
|
+
| `async_get_vehicle_status()` | Combined cached status and telemetry |
|
|
30
|
+
| `async_get_vehicle_battery_status()` | Battery level, cable state, charge state, range, and remaining time |
|
|
31
|
+
| `async_get_vehicle_climate_status()` | Cached cabin climate state |
|
|
32
|
+
| `async_get_vehicle_doors_status()` | Door and lock state |
|
|
33
|
+
| `async_get_vehicle_location()` | Last reported vehicle location |
|
|
34
|
+
| `async_get_vehicle_capabilities()` | Features reported for a vehicle |
|
|
35
|
+
| `async_get_charge_schedules()` | Recurring charging schedules |
|
|
36
|
+
| `async_get_climate_schedules()` | Recurring climate schedules |
|
|
37
|
+
| `async_get_vehicle_service_history()` | Service history entries |
|
|
38
|
+
|
|
39
|
+
Nullable service fields remain nullable in the returned models. Enum types with an
|
|
40
|
+
`UNKNOWN_VALUE` member preserve future upstream values without mapping them to a known state.
|
|
41
|
+
|
|
42
|
+
## Remote commands
|
|
43
|
+
|
|
44
|
+
State-changing methods require `read_only=False` when constructing the client.
|
|
45
|
+
|
|
46
|
+
| Method | Command |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| `async_start_climate()` / `async_stop_climate()` | Cabin climate |
|
|
49
|
+
| `async_start_charge()` / `async_stop_charge()` | Charging |
|
|
50
|
+
| `async_lock_doors()` / `async_unlock_doors()` | Door locks |
|
|
51
|
+
| `async_flash_lights()` | Exterior lights |
|
|
52
|
+
| `async_flash_lights_and_horn()` | Exterior lights and horn |
|
|
53
|
+
| `async_start_engine()` / `async_stop_engine()` | Remote engine start |
|
|
54
|
+
| `async_locate_vehicle()` | Vehicle location refresh |
|
|
55
|
+
| `async_refresh_vehicle_status()` | Vehicle status refresh |
|
|
56
|
+
|
|
57
|
+
Vehicle capabilities and account subscriptions determine whether a command is available.
|
|
58
|
+
Protected operations also use the request proof configured on the client when the service
|
|
59
|
+
requires it.
|
|
60
|
+
Most commands return a `ServiceRequest`; pass it to `async_wait_for_service_request()` to wait
|
|
61
|
+
for a terminal result.
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
request = await client.async_lock_doors(vin)
|
|
65
|
+
result = await client.async_wait_for_service_request(vin, request)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
All polling helpers raise `TimeoutError` when their configured deadline expires. A nullable
|
|
69
|
+
result therefore represents an upstream response, never a hidden polling timeout.
|
|
70
|
+
|
|
71
|
+
## Read-only policy
|
|
72
|
+
|
|
73
|
+
Read-only mode is enabled by default. A blocked mutation raises `ReadOnlyError` before sending
|
|
74
|
+
a network request. Applications should create write-enabled clients only for explicit user
|
|
75
|
+
actions.
|
|
76
|
+
|
|
77
|
+
## Errors
|
|
78
|
+
|
|
79
|
+
Catch `NissanError` for package-level handling, or use its specific subclasses:
|
|
80
|
+
`AuthenticationError`, `NetworkError`, `ApiError`, `GraphQLError`, `ResponseError`, and
|
|
81
|
+
`ReadOnlyError`.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Authentication and tokens
|
|
2
|
+
|
|
3
|
+
`NissanClient` accepts MyNISSAN credentials only when `async_authenticate()` is called. The
|
|
4
|
+
returned `Tokens` object contains the access, refresh, and optional ID tokens used by later
|
|
5
|
+
requests.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
tokens = await client.async_authenticate(email, password)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Applications should store replacement tokens whenever the listener is called. The listener
|
|
12
|
+
may be synchronous or asynchronous.
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
from pynissan import Country, NissanClient, Tokens
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async def save_tokens(tokens: Tokens) -> None:
|
|
19
|
+
await token_store.save(tokens)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
client = NissanClient(
|
|
23
|
+
session,
|
|
24
|
+
country=Country.US,
|
|
25
|
+
tokens=await token_store.load(),
|
|
26
|
+
token_listener=save_tokens,
|
|
27
|
+
oauth_device_id=stored_device_id,
|
|
28
|
+
)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The client refreshes expired access tokens before authenticated requests. Concurrent requests
|
|
32
|
+
share one refresh operation, and `token_listener` receives the replacement token set.
|
|
33
|
+
|
|
34
|
+
Persist `client.oauth_device_id` with the account record so a later client instance can reuse
|
|
35
|
+
the same OAuth device identity. Treat credentials, tokens, and the device identifier as
|
|
36
|
+
sensitive application data. Do not log or commit them.
|
|
37
|
+
|
|
38
|
+
## Protected requests
|
|
39
|
+
|
|
40
|
+
Account onboarding and some connected-service operations require current request proof.
|
|
41
|
+
Supply either a static pair or an async provider when constructing the client.
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from pynissan import NissanClient, RequestProof
|
|
45
|
+
|
|
46
|
+
client = NissanClient(
|
|
47
|
+
session,
|
|
48
|
+
tokens=tokens,
|
|
49
|
+
request_proof=RequestProof(api_attestation, device_status),
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For long-running applications, a provider can load or refresh the pair on demand:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
async def request_proof_provider(force_refresh: bool) -> RequestProof:
|
|
57
|
+
return await proof_store.load(force_refresh=force_refresh)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
client = NissanClient(
|
|
61
|
+
session,
|
|
62
|
+
tokens=tokens,
|
|
63
|
+
request_proof_provider=request_proof_provider,
|
|
64
|
+
)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The provider receives `False` for a normal request and `True` after the service rejects the
|
|
68
|
+
current proof. A static value and a provider cannot be supplied together.
|