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.
Files changed (227) hide show
  1. pynissan-0.1.0/CHANGELOG.md +75 -0
  2. pynissan-0.1.0/CONTRIBUTING.md +58 -0
  3. pynissan-0.1.0/LICENSE +21 -0
  4. pynissan-0.1.0/MANIFEST.in +5 -0
  5. pynissan-0.1.0/PKG-INFO +194 -0
  6. pynissan-0.1.0/README.md +157 -0
  7. pynissan-0.1.0/SECURITY.md +18 -0
  8. pynissan-0.1.0/docs/api.md +81 -0
  9. pynissan-0.1.0/docs/authentication.md +68 -0
  10. pynissan-0.1.0/docs/releasing.md +50 -0
  11. pynissan-0.1.0/pyproject.toml +93 -0
  12. pynissan-0.1.0/scripts/__init__.py +1 -0
  13. pynissan-0.1.0/scripts/check_file_size.py +52 -0
  14. pynissan-0.1.0/setup.cfg +4 -0
  15. pynissan-0.1.0/src/pynissan/__init__.py +1408 -0
  16. pynissan-0.1.0/src/pynissan/_account_client.py +321 -0
  17. pynissan-0.1.0/src/pynissan/_alert_client.py +457 -0
  18. pynissan-0.1.0/src/pynissan/_alert_models.py +125 -0
  19. pynissan-0.1.0/src/pynissan/_capability_models.py +90 -0
  20. pynissan-0.1.0/src/pynissan/_client_base.py +280 -0
  21. pynissan-0.1.0/src/pynissan/_client_helpers.py +148 -0
  22. pynissan-0.1.0/src/pynissan/_climate_charge_client.py +427 -0
  23. pynissan-0.1.0/src/pynissan/_commerce_catalog_parsing.py +139 -0
  24. pynissan-0.1.0/src/pynissan/_commerce_payment_parsing.py +191 -0
  25. pynissan-0.1.0/src/pynissan/_commerce_public_parsing.py +298 -0
  26. pynissan-0.1.0/src/pynissan/_commerce_value_parsing.py +104 -0
  27. pynissan-0.1.0/src/pynissan/_content_client.py +248 -0
  28. pynissan-0.1.0/src/pynissan/_core_models.py +184 -0
  29. pynissan-0.1.0/src/pynissan/_dealer_appointment_parsing.py +307 -0
  30. pynissan-0.1.0/src/pynissan/_dealer_client.py +381 -0
  31. pynissan-0.1.0/src/pynissan/_dealer_detail_parsing.py +212 -0
  32. pynissan-0.1.0/src/pynissan/_dealer_public_parsing.py +310 -0
  33. pynissan-0.1.0/src/pynissan/_dealer_value_parsing.py +110 -0
  34. pynissan-0.1.0/src/pynissan/_driver_client.py +198 -0
  35. pynissan-0.1.0/src/pynissan/_driver_detail_parsing.py +204 -0
  36. pynissan-0.1.0/src/pynissan/_driver_public_parsing.py +299 -0
  37. pynissan-0.1.0/src/pynissan/_driver_value_parsing.py +202 -0
  38. pynissan-0.1.0/src/pynissan/_energy_client.py +487 -0
  39. pynissan-0.1.0/src/pynissan/_energy_models.py +104 -0
  40. pynissan-0.1.0/src/pynissan/_extended_vehicle_driving_parsing.py +141 -0
  41. pynissan-0.1.0/src/pynissan/_extended_vehicle_location_parsing.py +298 -0
  42. pynissan-0.1.0/src/pynissan/_extended_vehicle_public_parsing.py +260 -0
  43. pynissan-0.1.0/src/pynissan/_extended_vehicle_tariff_parsing.py +250 -0
  44. pynissan-0.1.0/src/pynissan/_extended_vehicle_value_parsing.py +149 -0
  45. pynissan-0.1.0/src/pynissan/_finance_account_parsing.py +271 -0
  46. pynissan-0.1.0/src/pynissan/_finance_client.py +269 -0
  47. pynissan-0.1.0/src/pynissan/_finance_public_parsing.py +300 -0
  48. pynissan-0.1.0/src/pynissan/_finance_statement_parsing.py +282 -0
  49. pynissan-0.1.0/src/pynissan/_finance_value_parsing.py +88 -0
  50. pynissan-0.1.0/src/pynissan/_garage_client.py +312 -0
  51. pynissan-0.1.0/src/pynissan/_incident_client.py +179 -0
  52. pynissan-0.1.0/src/pynissan/_maintenance_detail_parsing.py +270 -0
  53. pynissan-0.1.0/src/pynissan/_maintenance_public_parsing.py +324 -0
  54. pynissan-0.1.0/src/pynissan/_maintenance_value_parsing.py +273 -0
  55. pynissan-0.1.0/src/pynissan/_message_client.py +112 -0
  56. pynissan-0.1.0/src/pynissan/_navigation_command_client.py +282 -0
  57. pynissan-0.1.0/src/pynissan/_navigation_public_parsing.py +370 -0
  58. pynissan-0.1.0/src/pynissan/_navigation_read_client.py +202 -0
  59. pynissan-0.1.0/src/pynissan/_navigation_value_parsing.py +114 -0
  60. pynissan-0.1.0/src/pynissan/_navigation_waypoint_parsing.py +273 -0
  61. pynissan-0.1.0/src/pynissan/_ota_notification_client.py +281 -0
  62. pynissan-0.1.0/src/pynissan/_parsing_values.py +230 -0
  63. pynissan-0.1.0/src/pynissan/_polling_client.py +103 -0
  64. pynissan-0.1.0/src/pynissan/_profile.py +84 -0
  65. pynissan-0.1.0/src/pynissan/_request_models.py +115 -0
  66. pynissan-0.1.0/src/pynissan/_second_delivery_client.py +227 -0
  67. pynissan-0.1.0/src/pynissan/_second_delivery_detail_parsing.py +412 -0
  68. pynissan-0.1.0/src/pynissan/_second_delivery_public_parsing.py +213 -0
  69. pynissan-0.1.0/src/pynissan/_second_delivery_value_parsing.py +77 -0
  70. pynissan-0.1.0/src/pynissan/_transport.py +483 -0
  71. pynissan-0.1.0/src/pynissan/_vehicle_alert_parsing.py +231 -0
  72. pynissan-0.1.0/src/pynissan/_vehicle_capability_parsing.py +161 -0
  73. pynissan-0.1.0/src/pynissan/_vehicle_command_client.py +293 -0
  74. pynissan-0.1.0/src/pynissan/_vehicle_core_parsing.py +312 -0
  75. pynissan-0.1.0/src/pynissan/_vehicle_data_client.py +315 -0
  76. pynissan-0.1.0/src/pynissan/_vehicle_detail_client.py +233 -0
  77. pynissan-0.1.0/src/pynissan/_vehicle_energy_parsing.py +196 -0
  78. pynissan-0.1.0/src/pynissan/_vehicle_models.py +141 -0
  79. pynissan-0.1.0/src/pynissan/_vehicle_response_parsing.py +235 -0
  80. pynissan-0.1.0/src/pynissan/_vehicle_status_models.py +135 -0
  81. pynissan-0.1.0/src/pynissan/_vehicle_subscription_parsing.py +253 -0
  82. pynissan-0.1.0/src/pynissan/_version.py +3 -0
  83. pynissan-0.1.0/src/pynissan/account_enrollment_parsing.py +343 -0
  84. pynissan-0.1.0/src/pynissan/account_inputs.py +287 -0
  85. pynissan-0.1.0/src/pynissan/account_models.py +526 -0
  86. pynissan-0.1.0/src/pynissan/account_parsing.py +508 -0
  87. pynissan-0.1.0/src/pynissan/alert_inputs.py +186 -0
  88. pynissan-0.1.0/src/pynissan/callbacks.py +13 -0
  89. pynissan-0.1.0/src/pynissan/charge_plan_inputs.py +37 -0
  90. pynissan-0.1.0/src/pynissan/charge_plan_models.py +107 -0
  91. pynissan-0.1.0/src/pynissan/charge_plan_parsing.py +237 -0
  92. pynissan-0.1.0/src/pynissan/client.py +43 -0
  93. pynissan-0.1.0/src/pynissan/collision_report_inputs.py +286 -0
  94. pynissan-0.1.0/src/pynissan/collision_report_models.py +150 -0
  95. pynissan-0.1.0/src/pynissan/collision_report_parsing.py +279 -0
  96. pynissan-0.1.0/src/pynissan/commerce_inputs.py +85 -0
  97. pynissan-0.1.0/src/pynissan/commerce_models.py +307 -0
  98. pynissan-0.1.0/src/pynissan/commerce_parsing.py +27 -0
  99. pynissan-0.1.0/src/pynissan/common_inputs.py +46 -0
  100. pynissan-0.1.0/src/pynissan/content_inputs.py +32 -0
  101. pynissan-0.1.0/src/pynissan/content_models.py +128 -0
  102. pynissan-0.1.0/src/pynissan/content_parsing.py +289 -0
  103. pynissan-0.1.0/src/pynissan/countries.py +7 -0
  104. pynissan-0.1.0/src/pynissan/dealer_inputs.py +373 -0
  105. pynissan-0.1.0/src/pynissan/dealer_models.py +357 -0
  106. pynissan-0.1.0/src/pynissan/dealer_parsing.py +39 -0
  107. pynissan-0.1.0/src/pynissan/device_notification_inputs.py +124 -0
  108. pynissan-0.1.0/src/pynissan/device_notification_models.py +60 -0
  109. pynissan-0.1.0/src/pynissan/device_notification_parsing.py +209 -0
  110. pynissan-0.1.0/src/pynissan/driver_inputs.py +251 -0
  111. pynissan-0.1.0/src/pynissan/driver_models.py +232 -0
  112. pynissan-0.1.0/src/pynissan/driver_parsing.py +29 -0
  113. pynissan-0.1.0/src/pynissan/energy_account_models.py +105 -0
  114. pynissan-0.1.0/src/pynissan/energy_account_parsing.py +160 -0
  115. pynissan-0.1.0/src/pynissan/exceptions.py +41 -0
  116. pynissan-0.1.0/src/pynissan/extended_vehicle_inputs.py +147 -0
  117. pynissan-0.1.0/src/pynissan/extended_vehicle_models.py +418 -0
  118. pynissan-0.1.0/src/pynissan/extended_vehicle_parsing.py +23 -0
  119. pynissan-0.1.0/src/pynissan/finance_inputs.py +138 -0
  120. pynissan-0.1.0/src/pynissan/finance_models.py +422 -0
  121. pynissan-0.1.0/src/pynissan/finance_parsing.py +37 -0
  122. pynissan-0.1.0/src/pynissan/garage_inputs.py +202 -0
  123. pynissan-0.1.0/src/pynissan/garage_models.py +311 -0
  124. pynissan-0.1.0/src/pynissan/garage_parsing.py +513 -0
  125. pynissan-0.1.0/src/pynissan/graphql_input.py +36 -0
  126. pynissan-0.1.0/src/pynissan/insurance_inputs.py +32 -0
  127. pynissan-0.1.0/src/pynissan/insurance_models.py +66 -0
  128. pynissan-0.1.0/src/pynissan/insurance_parsing.py +169 -0
  129. pynissan-0.1.0/src/pynissan/maintenance_inputs.py +275 -0
  130. pynissan-0.1.0/src/pynissan/maintenance_models.py +182 -0
  131. pynissan-0.1.0/src/pynissan/maintenance_parsing.py +29 -0
  132. pynissan-0.1.0/src/pynissan/models.py +239 -0
  133. pynissan-0.1.0/src/pynissan/navigation_inputs.py +392 -0
  134. pynissan-0.1.0/src/pynissan/navigation_models.py +321 -0
  135. pynissan-0.1.0/src/pynissan/navigation_parsing.py +19 -0
  136. pynissan-0.1.0/src/pynissan/notification_inputs.py +82 -0
  137. pynissan-0.1.0/src/pynissan/notification_models.py +100 -0
  138. pynissan-0.1.0/src/pynissan/notification_parsing.py +214 -0
  139. pynissan-0.1.0/src/pynissan/operations.py +1522 -0
  140. pynissan-0.1.0/src/pynissan/ota_inputs.py +30 -0
  141. pynissan-0.1.0/src/pynissan/ota_models.py +90 -0
  142. pynissan-0.1.0/src/pynissan/ota_parsing.py +214 -0
  143. pynissan-0.1.0/src/pynissan/parsing.py +65 -0
  144. pynissan-0.1.0/src/pynissan/pnc_inputs.py +49 -0
  145. pynissan-0.1.0/src/pynissan/pnc_models.py +199 -0
  146. pynissan-0.1.0/src/pynissan/pnc_parsing.py +276 -0
  147. pynissan-0.1.0/src/pynissan/py.typed +1 -0
  148. pynissan-0.1.0/src/pynissan/request_proof.py +13 -0
  149. pynissan-0.1.0/src/pynissan/second_delivery_inputs.py +157 -0
  150. pynissan-0.1.0/src/pynissan/second_delivery_models.py +292 -0
  151. pynissan-0.1.0/src/pynissan/second_delivery_parsing.py +29 -0
  152. pynissan-0.1.0/src/pynissan/service_inputs.py +48 -0
  153. pynissan-0.1.0/src/pynissan/service_models.py +153 -0
  154. pynissan-0.1.0/src/pynissan/service_parsing.py +531 -0
  155. pynissan-0.1.0/src/pynissan/v1g_inputs.py +104 -0
  156. pynissan-0.1.0/src/pynissan/v1g_models.py +108 -0
  157. pynissan-0.1.0/src/pynissan/v1g_parsing.py +282 -0
  158. pynissan-0.1.0/src/pynissan/vehicle_detail_inputs.py +114 -0
  159. pynissan-0.1.0/src/pynissan/vehicle_detail_models.py +31 -0
  160. pynissan-0.1.0/src/pynissan/vehicle_detail_parsing.py +177 -0
  161. pynissan-0.1.0/src/pynissan/wearable_models.py +27 -0
  162. pynissan-0.1.0/src/pynissan/wearable_parsing.py +127 -0
  163. pynissan-0.1.0/src/pynissan.egg-info/PKG-INFO +194 -0
  164. pynissan-0.1.0/src/pynissan.egg-info/SOURCES.txt +225 -0
  165. pynissan-0.1.0/src/pynissan.egg-info/dependency_links.txt +1 -0
  166. pynissan-0.1.0/src/pynissan.egg-info/requires.txt +10 -0
  167. pynissan-0.1.0/src/pynissan.egg-info/top_level.txt +1 -0
  168. pynissan-0.1.0/tests/test_account_inputs_and_queries.py +309 -0
  169. pynissan-0.1.0/tests/test_account_mutations.py +442 -0
  170. pynissan-0.1.0/tests/test_account_vehicle_client.py +491 -0
  171. pynissan-0.1.0/tests/test_charge_plans.py +493 -0
  172. pynissan-0.1.0/tests/test_client.py +118 -0
  173. pynissan-0.1.0/tests/test_client_part_01.py +336 -0
  174. pynissan-0.1.0/tests/test_client_part_02.py +313 -0
  175. pynissan-0.1.0/tests/test_client_part_03.py +313 -0
  176. pynissan-0.1.0/tests/test_client_part_04.py +336 -0
  177. pynissan-0.1.0/tests/test_client_part_05.py +318 -0
  178. pynissan-0.1.0/tests/test_client_part_06.py +340 -0
  179. pynissan-0.1.0/tests/test_client_part_07.py +270 -0
  180. pynissan-0.1.0/tests/test_client_part_08.py +314 -0
  181. pynissan-0.1.0/tests/test_client_part_09.py +335 -0
  182. pynissan-0.1.0/tests/test_client_part_10.py +334 -0
  183. pynissan-0.1.0/tests/test_client_part_11.py +274 -0
  184. pynissan-0.1.0/tests/test_client_part_12.py +283 -0
  185. pynissan-0.1.0/tests/test_client_part_13.py +333 -0
  186. pynissan-0.1.0/tests/test_client_part_14.py +328 -0
  187. pynissan-0.1.0/tests/test_client_part_15.py +197 -0
  188. pynissan-0.1.0/tests/test_commerce.py +81 -0
  189. pynissan-0.1.0/tests/test_commerce_part_01.py +312 -0
  190. pynissan-0.1.0/tests/test_commerce_part_02.py +216 -0
  191. pynissan-0.1.0/tests/test_content_and_support.py +271 -0
  192. pynissan-0.1.0/tests/test_dealers_and_service_appointments.py +416 -0
  193. pynissan-0.1.0/tests/test_device_notifications.py +521 -0
  194. pynissan-0.1.0/tests/test_drivers.py +88 -0
  195. pynissan-0.1.0/tests/test_drivers_part_01.py +347 -0
  196. pynissan-0.1.0/tests/test_drivers_part_02.py +280 -0
  197. pynissan-0.1.0/tests/test_drivers_part_03.py +115 -0
  198. pynissan-0.1.0/tests/test_energy_account.py +378 -0
  199. pynissan-0.1.0/tests/test_energy_client.py +209 -0
  200. pynissan-0.1.0/tests/test_energy_notifications.py +253 -0
  201. pynissan-0.1.0/tests/test_extended_vehicle_reads.py +83 -0
  202. pynissan-0.1.0/tests/test_extended_vehicle_reads_part_01.py +308 -0
  203. pynissan-0.1.0/tests/test_extended_vehicle_reads_part_02.py +277 -0
  204. pynissan-0.1.0/tests/test_extended_vehicle_reads_part_03.py +266 -0
  205. pynissan-0.1.0/tests/test_extended_vehicle_reads_part_04.py +176 -0
  206. pynissan-0.1.0/tests/test_finance.py +370 -0
  207. pynissan-0.1.0/tests/test_garage.py +93 -0
  208. pynissan-0.1.0/tests/test_garage_part_01.py +374 -0
  209. pynissan-0.1.0/tests/test_garage_part_02.py +338 -0
  210. pynissan-0.1.0/tests/test_garage_part_03.py +214 -0
  211. pynissan-0.1.0/tests/test_insurance_and_collision_reports.py +417 -0
  212. pynissan-0.1.0/tests/test_maintenance.py +124 -0
  213. pynissan-0.1.0/tests/test_maintenance_part_01.py +368 -0
  214. pynissan-0.1.0/tests/test_maintenance_part_02.py +317 -0
  215. pynissan-0.1.0/tests/test_operation_catalog.py +19 -0
  216. pynissan-0.1.0/tests/test_pnc.py +82 -0
  217. pynissan-0.1.0/tests/test_pnc_part_01.py +310 -0
  218. pynissan-0.1.0/tests/test_pnc_part_02.py +309 -0
  219. pynissan-0.1.0/tests/test_public_api.py +37 -0
  220. pynissan-0.1.0/tests/test_safety_contracts.py +84 -0
  221. pynissan-0.1.0/tests/test_second_delivery.py +412 -0
  222. pynissan-0.1.0/tests/test_service_reads.py +196 -0
  223. pynissan-0.1.0/tests/test_service_reads_part_01.py +324 -0
  224. pynissan-0.1.0/tests/test_service_reads_part_02.py +113 -0
  225. pynissan-0.1.0/tests/test_v1g.py +460 -0
  226. pynissan-0.1.0/tests/test_vehicle_detail_reads.py +334 -0
  227. 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.
@@ -0,0 +1,5 @@
1
+ include CHANGELOG.md
2
+ include CONTRIBUTING.md
3
+ include SECURITY.md
4
+ recursive-include docs *.md
5
+ recursive-include scripts *.py
@@ -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
+ [![CI](https://github.com/bvdcode/nissan-connect-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/bvdcode/nissan-connect-sdk/actions/workflows/ci.yml)
41
+ [![PyPI](https://img.shields.io/pypi/v/pynissan.svg)](https://pypi.org/project/pynissan/)
42
+ [![Python](https://img.shields.io/pypi/pyversions/pynissan.svg)](https://pypi.org/project/pynissan/)
43
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](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.
@@ -0,0 +1,157 @@
1
+ # pynissan
2
+
3
+ [![CI](https://github.com/bvdcode/nissan-connect-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/bvdcode/nissan-connect-sdk/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/pynissan.svg)](https://pypi.org/project/pynissan/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/pynissan.svg)](https://pypi.org/project/pynissan/)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](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.