pyfordpass 0.0.1__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 (69) hide show
  1. pyfordpass-0.0.1/.gitignore +36 -0
  2. pyfordpass-0.0.1/LICENSE.txt +18 -0
  3. pyfordpass-0.0.1/PKG-INFO +164 -0
  4. pyfordpass-0.0.1/README.md +132 -0
  5. pyfordpass-0.0.1/fordpass/__init__.py +17 -0
  6. pyfordpass-0.0.1/fordpass/__main__.py +6 -0
  7. pyfordpass-0.0.1/fordpass/api_config.py +105 -0
  8. pyfordpass-0.0.1/fordpass/client.py +1341 -0
  9. pyfordpass-0.0.1/fordpass/commands/__init__.py +1 -0
  10. pyfordpass-0.0.1/fordpass/commands/alerts.py +103 -0
  11. pyfordpass-0.0.1/fordpass/commands/api_config.py +60 -0
  12. pyfordpass-0.0.1/fordpass/commands/auth.py +84 -0
  13. pyfordpass-0.0.1/fordpass/commands/config.py +60 -0
  14. pyfordpass-0.0.1/fordpass/commands/dealer.py +52 -0
  15. pyfordpass-0.0.1/fordpass/commands/departure.py +52 -0
  16. pyfordpass-0.0.1/fordpass/commands/drivers.py +97 -0
  17. pyfordpass-0.0.1/fordpass/commands/messages.py +146 -0
  18. pyfordpass-0.0.1/fordpass/commands/ota.py +146 -0
  19. pyfordpass-0.0.1/fordpass/commands/profile.py +104 -0
  20. pyfordpass-0.0.1/fordpass/commands/remote.py +108 -0
  21. pyfordpass-0.0.1/fordpass/commands/roadside.py +114 -0
  22. pyfordpass-0.0.1/fordpass/commands/schedule.py +282 -0
  23. pyfordpass-0.0.1/fordpass/commands/service.py +346 -0
  24. pyfordpass-0.0.1/fordpass/commands/telemetry.py +798 -0
  25. pyfordpass-0.0.1/fordpass/commands/utils.py +1224 -0
  26. pyfordpass-0.0.1/fordpass/commands/vehicle.py +338 -0
  27. pyfordpass-0.0.1/fordpass/config.py +306 -0
  28. pyfordpass-0.0.1/fordpass/main.py +61 -0
  29. pyfordpass-0.0.1/fordpass/py.typed +0 -0
  30. pyfordpass-0.0.1/fordpass/sansio.py +1611 -0
  31. pyfordpass-0.0.1/fordpass/timezone_map.py +438 -0
  32. pyfordpass-0.0.1/fordpass/typing/__init__.py +170 -0
  33. pyfordpass-0.0.1/fordpass/typing/alerts.py +125 -0
  34. pyfordpass-0.0.1/fordpass/typing/api_config.py +78 -0
  35. pyfordpass-0.0.1/fordpass/typing/auth.py +56 -0
  36. pyfordpass-0.0.1/fordpass/typing/commands.py +15 -0
  37. pyfordpass-0.0.1/fordpass/typing/common.py +87 -0
  38. pyfordpass-0.0.1/fordpass/typing/config.py +63 -0
  39. pyfordpass-0.0.1/fordpass/typing/dealer.py +20 -0
  40. pyfordpass-0.0.1/fordpass/typing/drivers.py +53 -0
  41. pyfordpass-0.0.1/fordpass/typing/messages.py +58 -0
  42. pyfordpass-0.0.1/fordpass/typing/profile.py +152 -0
  43. pyfordpass-0.0.1/fordpass/typing/release.py +13 -0
  44. pyfordpass-0.0.1/fordpass/typing/roadside.py +34 -0
  45. pyfordpass-0.0.1/fordpass/typing/schedule.py +60 -0
  46. pyfordpass-0.0.1/fordpass/typing/service.py +107 -0
  47. pyfordpass-0.0.1/fordpass/typing/telemetry.py +91 -0
  48. pyfordpass-0.0.1/fordpass/typing/vehicle.py +201 -0
  49. pyfordpass-0.0.1/fordpass/utils.py +272 -0
  50. pyfordpass-0.0.1/man/fordpass.1 +2416 -0
  51. pyfordpass-0.0.1/pyproject.toml +268 -0
  52. pyfordpass-0.0.1/tests/conftest.py +206 -0
  53. pyfordpass-0.0.1/tests/pyproject.toml +27 -0
  54. pyfordpass-0.0.1/tests/test_api_config.py +89 -0
  55. pyfordpass-0.0.1/tests/test_client.py +634 -0
  56. pyfordpass-0.0.1/tests/test_commands_api_config.py +93 -0
  57. pyfordpass-0.0.1/tests/test_commands_auth.py +80 -0
  58. pyfordpass-0.0.1/tests/test_commands_config.py +67 -0
  59. pyfordpass-0.0.1/tests/test_commands_data.py +395 -0
  60. pyfordpass-0.0.1/tests/test_commands_schedule.py +203 -0
  61. pyfordpass-0.0.1/tests/test_commands_service.py +300 -0
  62. pyfordpass-0.0.1/tests/test_commands_simple.py +328 -0
  63. pyfordpass-0.0.1/tests/test_commands_telemetry.py +512 -0
  64. pyfordpass-0.0.1/tests/test_commands_utils.py +598 -0
  65. pyfordpass-0.0.1/tests/test_commands_vehicle.py +229 -0
  66. pyfordpass-0.0.1/tests/test_config.py +223 -0
  67. pyfordpass-0.0.1/tests/test_main.py +22 -0
  68. pyfordpass-0.0.1/tests/test_sansio.py +505 -0
  69. pyfordpass-0.0.1/tests/test_utils.py +319 -0
@@ -0,0 +1,36 @@
1
+ *.kate-swp
2
+ *.log
3
+ *~
4
+ .*.swp
5
+ .*_cache/
6
+ .DS_Store*
7
+ .coverage
8
+ .cspellcache
9
+ .directory
10
+ .pnp.*
11
+ .venv/
12
+ /.bash_profile
13
+ /.bashrc
14
+ /.claude/commands
15
+ /.claude/settings.local.json
16
+ /.gitconfig
17
+ /.gitmodules
18
+ /.idea
19
+ /.mcp.json
20
+ /.profile
21
+ /.ripgreprc
22
+ /.wiswa-ci/
23
+ /.yarn/install-state.gz
24
+ /.zprofile
25
+ /.zshrc
26
+ /build/
27
+ /dist/
28
+ /docs/_build/
29
+ /man/_static/
30
+ /mypy-report*/
31
+ __pycache__/
32
+ cobertura.xml
33
+ coverage.xml
34
+ htmlcov/
35
+ mypy-report.xml
36
+ node_modules/
@@ -0,0 +1,18 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 pyfordpass authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6
+ associated documentation files (the "Software"), to deal in the Software without restriction,
7
+ including without limitation the rights to use, copy, modify, merge, publish, distribute,
8
+ sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or
12
+ substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
15
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
18
+ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyfordpass
3
+ Version: 0.0.1
4
+ Summary: FordPass client and CLI.
5
+ Project-URL: Issues, https://github.com/Tatsh/pyfordpass/issues
6
+ Project-URL: documentation, https://pyfordpass.readthedocs.org
7
+ Project-URL: homepage, https://tatsh.github.io/pyfordpass/
8
+ Project-URL: repository, https://github.com/Tatsh/pyfordpass
9
+ Author-email: Andrew Udvare <audvare@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE.txt
12
+ Keywords: command line,ford,fordpass
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: <4.0,>=3.10
23
+ Requires-Dist: bascom>=0.1.3
24
+ Requires-Dist: click>=8.4.1
25
+ Requires-Dist: curl-cffi>=0.15.0
26
+ Requires-Dist: niquests>=3.18.8
27
+ Requires-Dist: platformdirs>=4.9.6
28
+ Requires-Dist: rich>=15.0.0
29
+ Requires-Dist: tomlkit>=0.15.0
30
+ Requires-Dist: typing-extensions>=4.15.0
31
+ Description-Content-Type: text/markdown
32
+
33
+ # pyfordpass
34
+
35
+ <!-- WISWA-GENERATED-README:START -->
36
+
37
+ [![Python versions](https://img.shields.io/pypi/pyversions/pyfordpass.svg?color=blue&logo=python&logoColor=white)](https://www.python.org/)
38
+ [![PyPI - Version](https://img.shields.io/pypi/v/pyfordpass)](https://pypi.org/project/pyfordpass/)
39
+ [![GitHub tag (with filter)](https://img.shields.io/github/v/tag/Tatsh/pyfordpass)](https://github.com/Tatsh/pyfordpass/tags)
40
+ [![License](https://img.shields.io/github/license/Tatsh/pyfordpass)](https://github.com/Tatsh/pyfordpass/blob/master/LICENSE.txt)
41
+ [![GitHub commits since latest release (by SemVer including pre-releases)](https://img.shields.io/github/commits-since/Tatsh/pyfordpass/v0.0.1/master)](https://github.com/Tatsh/pyfordpass/compare/v0.0.1...master)
42
+ [![CodeQL](https://github.com/Tatsh/pyfordpass/actions/workflows/codeql.yml/badge.svg)](https://github.com/Tatsh/pyfordpass/actions/workflows/codeql.yml)
43
+ [![QA](https://github.com/Tatsh/pyfordpass/actions/workflows/qa.yml/badge.svg)](https://github.com/Tatsh/pyfordpass/actions/workflows/qa.yml)
44
+ [![Tests](https://github.com/Tatsh/pyfordpass/actions/workflows/tests.yml/badge.svg)](https://github.com/Tatsh/pyfordpass/actions/workflows/tests.yml)
45
+ [![Coverage Status](https://coveralls.io/repos/github/Tatsh/pyfordpass/badge.svg?branch=master)](https://coveralls.io/github/Tatsh/pyfordpass?branch=master)
46
+ [![Dependabot](https://img.shields.io/badge/Dependabot-enabled-blue?logo=dependabot)](https://github.com/dependabot)
47
+ [![Documentation Status](https://readthedocs.org/projects/pyfordpass/badge/?version=latest)](https://pyfordpass.readthedocs.org/?badge=latest)
48
+ [![mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
49
+ [![uv](https://img.shields.io/badge/uv-261230?logo=astral)](https://docs.astral.sh/uv/)
50
+ [![pytest](https://img.shields.io/badge/pytest-zz?logo=Pytest&labelColor=black&color=black)](https://docs.pytest.org/en/stable/)
51
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
52
+ [![Downloads](https://static.pepy.tech/badge/pyfordpass/month)](https://pepy.tech/project/pyfordpass)
53
+ [![Stargazers](https://img.shields.io/github/stars/Tatsh/pyfordpass?logo=github&style=flat)](https://github.com/Tatsh/pyfordpass/stargazers)
54
+ [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)
55
+ [![Prettier](https://img.shields.io/badge/Prettier-black?logo=prettier)](https://prettier.io/)
56
+
57
+ [![@Tatsh](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fpublic.api.bsky.app%2Fxrpc%2Fapp.bsky.actor.getProfile%2F%3Factor=did%3Aplc%3Auq42idtvuccnmtl57nsucz72&query=%24.followersCount&label=Follow+%40Tatsh&logo=bluesky&style=social)](https://bsky.app/profile/Tatsh.bsky.social)
58
+ [![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Tatsh-black?logo=buymeacoffee)](https://buymeacoffee.com/Tatsh)
59
+ [![Libera.Chat](https://img.shields.io/badge/Libera.Chat-Tatsh-black?logo=liberadotchat)](irc://irc.libera.chat/Tatsh)
60
+ [![Mastodon Follow](https://img.shields.io/mastodon/follow/109370961877277568?domain=hostux.social&style=social)](https://hostux.social/@Tatsh)
61
+ [![Patreon](https://img.shields.io/badge/Patreon-Tatsh2-F96854?logo=patreon)](https://www.patreon.com/Tatsh2)
62
+
63
+ <!-- WISWA-GENERATED-README:STOP -->
64
+
65
+ FordPass client and CLI. A third-party reverse-engineered client for the same private mobile-app
66
+ endpoints the FordPass™ app uses, packaged as a Python library plus a `fordpass` command-line
67
+ tool.
68
+
69
+ ## Disclaimer
70
+
71
+ This project is **not** an official Ford product. It is **not** affiliated with, endorsed by,
72
+ sponsored by, or otherwise connected to Ford Motor Company or any of its subsidiaries.
73
+ "FordPass", "The Lincoln Way", "Ford", and "Lincoln" are trademarks of Ford Motor Company.
74
+
75
+ Because this client speaks to private endpoints rather than a documented public API, Ford may
76
+ change, throttle, or revoke access without notice - and the maintainer cannot guarantee that any
77
+ particular feature will keep working.
78
+
79
+ > **Use of this software may cause your FordPass™ / The Lincoln Way™ account to be (temporarily)
80
+ > locked or suspended.** Traffic from any unofficial client can look anomalous to Ford's fraud
81
+ > and abuse detection. **Use at your own risk.**
82
+
83
+ It is **strongly recommended** to use a **separate, secondary FordPass™ account** for this
84
+ software rather than your primary account:
85
+
86
+ 1. In the FordPass app on a phone (signed in as the primary owner), invite a secondary email
87
+ address as an additional driver for the vehicle. The invited address must be reachable from
88
+ that phone for verification.
89
+ 2. Sign up for a new FordPass account using that secondary email and accept the driver
90
+ invitation.
91
+ 3. Configure `pyfordpass` (`fordpass auth login`) with the secondary account's credentials.
92
+
93
+ If the secondary account is later suspended, your primary account, warranty records, and
94
+ roadside-assistance enrolment remain unaffected.
95
+
96
+ See the [ha-fordpass project's general disclaimer and account-setup
97
+ guidance](https://github.com/marq24/ha-fordpass#general-disclaimer) for the same procedure
98
+ written up from the Home Assistant integration's perspective - the steps are identical
99
+ regardless of which third-party client consumes the credentials.
100
+
101
+ ## Installation
102
+
103
+ ```shell
104
+ pip install pyfordpass
105
+ ```
106
+
107
+ ## Usage
108
+
109
+ Add `-d` to show debug logs. Run with no arguments to see the top-level command list:
110
+
111
+ ```shell
112
+ fordpass
113
+ ```
114
+
115
+ A typical first-time flow:
116
+
117
+ ```shell
118
+ fordpass auth login # Interactive sign-in against the secondary account.
119
+ fordpass vehicle list # See what's in the garage.
120
+ fordpass vehicle show VIN # Detailed view for one vehicle.
121
+ fordpass remote start VIN # Remote-start command.
122
+ ```
123
+
124
+ Every subcommand supports `--help` and most data-returning subcommands support `--json` for
125
+ machine-readable output.
126
+
127
+ ## Configuration
128
+
129
+ `pyfordpass` has two sets of optional settings, each managed with its own subcommand rather than
130
+ by editing files by hand. Both live under `~/.config/pyfordpass` on Linux (the platform-specific
131
+ equivalent elsewhere).
132
+
133
+ **User preferences** are managed with `fordpass config`. The most useful is a default VIN, so you
134
+ need not pass it to every command:
135
+
136
+ ```shell
137
+ # Set a default VIN, used whenever a command's VIN argument is omitted.
138
+ fordpass config set vehicle.default_vin VIN
139
+ # Distance ("mi"/"km") and temperature ("F"/"C"); both default from your locale.
140
+ fordpass config set units.distance mi
141
+ fordpass config set units.temperature C
142
+ # Default output format: "pretty" (Rich tables) or "json".
143
+ fordpass config set output.format json
144
+ # Show the effective configuration (defaults included), drop a key, or start over.
145
+ fordpass config dump
146
+ fordpass config delete units.distance
147
+ fordpass config reset
148
+ ```
149
+
150
+ **API constants** are managed with `fordpass api-config`. The built-in defaults target Ford in the
151
+ USA, so most users never need to touch them. When Ford rotates a host or client ID you can patch
152
+ individual values without waiting for a new release; anything you set is merged over the defaults,
153
+ so only the changed keys are required:
154
+
155
+ ```shell
156
+ # Override a single value; everything else falls back to the built-in defaults.
157
+ fordpass api-config set hosts.login https://login.ford.com
158
+ # Show the effective constants (defaults merged with overrides), or discard all overrides.
159
+ fordpass api-config dump
160
+ fordpass api-config reset
161
+ ```
162
+
163
+ Values for other regions and for Lincoln can be copied from
164
+ [ha-fordpass `const.py`](https://github.com/marq24/ha-fordpass/blob/main/custom_components/fordpass/const.py).
@@ -0,0 +1,132 @@
1
+ # pyfordpass
2
+
3
+ <!-- WISWA-GENERATED-README:START -->
4
+
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/pyfordpass.svg?color=blue&logo=python&logoColor=white)](https://www.python.org/)
6
+ [![PyPI - Version](https://img.shields.io/pypi/v/pyfordpass)](https://pypi.org/project/pyfordpass/)
7
+ [![GitHub tag (with filter)](https://img.shields.io/github/v/tag/Tatsh/pyfordpass)](https://github.com/Tatsh/pyfordpass/tags)
8
+ [![License](https://img.shields.io/github/license/Tatsh/pyfordpass)](https://github.com/Tatsh/pyfordpass/blob/master/LICENSE.txt)
9
+ [![GitHub commits since latest release (by SemVer including pre-releases)](https://img.shields.io/github/commits-since/Tatsh/pyfordpass/v0.0.1/master)](https://github.com/Tatsh/pyfordpass/compare/v0.0.1...master)
10
+ [![CodeQL](https://github.com/Tatsh/pyfordpass/actions/workflows/codeql.yml/badge.svg)](https://github.com/Tatsh/pyfordpass/actions/workflows/codeql.yml)
11
+ [![QA](https://github.com/Tatsh/pyfordpass/actions/workflows/qa.yml/badge.svg)](https://github.com/Tatsh/pyfordpass/actions/workflows/qa.yml)
12
+ [![Tests](https://github.com/Tatsh/pyfordpass/actions/workflows/tests.yml/badge.svg)](https://github.com/Tatsh/pyfordpass/actions/workflows/tests.yml)
13
+ [![Coverage Status](https://coveralls.io/repos/github/Tatsh/pyfordpass/badge.svg?branch=master)](https://coveralls.io/github/Tatsh/pyfordpass?branch=master)
14
+ [![Dependabot](https://img.shields.io/badge/Dependabot-enabled-blue?logo=dependabot)](https://github.com/dependabot)
15
+ [![Documentation Status](https://readthedocs.org/projects/pyfordpass/badge/?version=latest)](https://pyfordpass.readthedocs.org/?badge=latest)
16
+ [![mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
17
+ [![uv](https://img.shields.io/badge/uv-261230?logo=astral)](https://docs.astral.sh/uv/)
18
+ [![pytest](https://img.shields.io/badge/pytest-zz?logo=Pytest&labelColor=black&color=black)](https://docs.pytest.org/en/stable/)
19
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
20
+ [![Downloads](https://static.pepy.tech/badge/pyfordpass/month)](https://pepy.tech/project/pyfordpass)
21
+ [![Stargazers](https://img.shields.io/github/stars/Tatsh/pyfordpass?logo=github&style=flat)](https://github.com/Tatsh/pyfordpass/stargazers)
22
+ [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)
23
+ [![Prettier](https://img.shields.io/badge/Prettier-black?logo=prettier)](https://prettier.io/)
24
+
25
+ [![@Tatsh](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fpublic.api.bsky.app%2Fxrpc%2Fapp.bsky.actor.getProfile%2F%3Factor=did%3Aplc%3Auq42idtvuccnmtl57nsucz72&query=%24.followersCount&label=Follow+%40Tatsh&logo=bluesky&style=social)](https://bsky.app/profile/Tatsh.bsky.social)
26
+ [![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Tatsh-black?logo=buymeacoffee)](https://buymeacoffee.com/Tatsh)
27
+ [![Libera.Chat](https://img.shields.io/badge/Libera.Chat-Tatsh-black?logo=liberadotchat)](irc://irc.libera.chat/Tatsh)
28
+ [![Mastodon Follow](https://img.shields.io/mastodon/follow/109370961877277568?domain=hostux.social&style=social)](https://hostux.social/@Tatsh)
29
+ [![Patreon](https://img.shields.io/badge/Patreon-Tatsh2-F96854?logo=patreon)](https://www.patreon.com/Tatsh2)
30
+
31
+ <!-- WISWA-GENERATED-README:STOP -->
32
+
33
+ FordPass client and CLI. A third-party reverse-engineered client for the same private mobile-app
34
+ endpoints the FordPass™ app uses, packaged as a Python library plus a `fordpass` command-line
35
+ tool.
36
+
37
+ ## Disclaimer
38
+
39
+ This project is **not** an official Ford product. It is **not** affiliated with, endorsed by,
40
+ sponsored by, or otherwise connected to Ford Motor Company or any of its subsidiaries.
41
+ "FordPass", "The Lincoln Way", "Ford", and "Lincoln" are trademarks of Ford Motor Company.
42
+
43
+ Because this client speaks to private endpoints rather than a documented public API, Ford may
44
+ change, throttle, or revoke access without notice - and the maintainer cannot guarantee that any
45
+ particular feature will keep working.
46
+
47
+ > **Use of this software may cause your FordPass™ / The Lincoln Way™ account to be (temporarily)
48
+ > locked or suspended.** Traffic from any unofficial client can look anomalous to Ford's fraud
49
+ > and abuse detection. **Use at your own risk.**
50
+
51
+ It is **strongly recommended** to use a **separate, secondary FordPass™ account** for this
52
+ software rather than your primary account:
53
+
54
+ 1. In the FordPass app on a phone (signed in as the primary owner), invite a secondary email
55
+ address as an additional driver for the vehicle. The invited address must be reachable from
56
+ that phone for verification.
57
+ 2. Sign up for a new FordPass account using that secondary email and accept the driver
58
+ invitation.
59
+ 3. Configure `pyfordpass` (`fordpass auth login`) with the secondary account's credentials.
60
+
61
+ If the secondary account is later suspended, your primary account, warranty records, and
62
+ roadside-assistance enrolment remain unaffected.
63
+
64
+ See the [ha-fordpass project's general disclaimer and account-setup
65
+ guidance](https://github.com/marq24/ha-fordpass#general-disclaimer) for the same procedure
66
+ written up from the Home Assistant integration's perspective - the steps are identical
67
+ regardless of which third-party client consumes the credentials.
68
+
69
+ ## Installation
70
+
71
+ ```shell
72
+ pip install pyfordpass
73
+ ```
74
+
75
+ ## Usage
76
+
77
+ Add `-d` to show debug logs. Run with no arguments to see the top-level command list:
78
+
79
+ ```shell
80
+ fordpass
81
+ ```
82
+
83
+ A typical first-time flow:
84
+
85
+ ```shell
86
+ fordpass auth login # Interactive sign-in against the secondary account.
87
+ fordpass vehicle list # See what's in the garage.
88
+ fordpass vehicle show VIN # Detailed view for one vehicle.
89
+ fordpass remote start VIN # Remote-start command.
90
+ ```
91
+
92
+ Every subcommand supports `--help` and most data-returning subcommands support `--json` for
93
+ machine-readable output.
94
+
95
+ ## Configuration
96
+
97
+ `pyfordpass` has two sets of optional settings, each managed with its own subcommand rather than
98
+ by editing files by hand. Both live under `~/.config/pyfordpass` on Linux (the platform-specific
99
+ equivalent elsewhere).
100
+
101
+ **User preferences** are managed with `fordpass config`. The most useful is a default VIN, so you
102
+ need not pass it to every command:
103
+
104
+ ```shell
105
+ # Set a default VIN, used whenever a command's VIN argument is omitted.
106
+ fordpass config set vehicle.default_vin VIN
107
+ # Distance ("mi"/"km") and temperature ("F"/"C"); both default from your locale.
108
+ fordpass config set units.distance mi
109
+ fordpass config set units.temperature C
110
+ # Default output format: "pretty" (Rich tables) or "json".
111
+ fordpass config set output.format json
112
+ # Show the effective configuration (defaults included), drop a key, or start over.
113
+ fordpass config dump
114
+ fordpass config delete units.distance
115
+ fordpass config reset
116
+ ```
117
+
118
+ **API constants** are managed with `fordpass api-config`. The built-in defaults target Ford in the
119
+ USA, so most users never need to touch them. When Ford rotates a host or client ID you can patch
120
+ individual values without waiting for a new release; anything you set is merged over the defaults,
121
+ so only the changed keys are required:
122
+
123
+ ```shell
124
+ # Override a single value; everything else falls back to the built-in defaults.
125
+ fordpass api-config set hosts.login https://login.ford.com
126
+ # Show the effective constants (defaults merged with overrides), or discard all overrides.
127
+ fordpass api-config dump
128
+ fordpass api-config reset
129
+ ```
130
+
131
+ Values for other regions and for Lincoln can be copied from
132
+ [ha-fordpass `const.py`](https://github.com/marq24/ha-fordpass/blob/main/custom_components/fordpass/const.py).
@@ -0,0 +1,17 @@
1
+ """
2
+ FordPass client.
3
+
4
+ Public surface:
5
+
6
+ - :class:`fordpass.sansio.FordPassClient` - sans-I/O protocol core that builds
7
+ :class:`fordpass.sansio.RequestDict` descriptors.
8
+ - :class:`fordpass.client.AsyncFordPassClient` - fully-async niquests wrapper.
9
+ - ``fordpass`` command-line tool exposed via :mod:`fordpass.commands`.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ from .client import AsyncFordPassClient
14
+ from .sansio import FordPassClient, RequestDict
15
+
16
+ __all__ = ('AsyncFordPassClient', 'FordPassClient', 'RequestDict')
17
+ __version__ = '0.0.1'
@@ -0,0 +1,6 @@
1
+ """Entry point for ``python -m fordpass`` invocation."""
2
+ from __future__ import annotations
3
+
4
+ from fordpass.main import main
5
+
6
+ main()
@@ -0,0 +1,105 @@
1
+ """Loader for FordPass API constants."""
2
+ from __future__ import annotations
3
+
4
+ from collections.abc import Mapping
5
+ from typing import TYPE_CHECKING, Any, cast
6
+ import copy
7
+ import functools
8
+
9
+ from fordpass.config import CONFIG_DIR
10
+ import tomlkit
11
+
12
+ if TYPE_CHECKING:
13
+ from .typing.api_config import APIConfig
14
+
15
+ __all__ = ('API_CONFIG_FILE', 'DEFAULT_API_CONFIG', 'load_api_config')
16
+
17
+ API_CONFIG_FILE = CONFIG_DIR / 'api.toml'
18
+ """
19
+ Path to the optional constants-override TOML file.
20
+
21
+ When present, its contents are merged over :data:`DEFAULT_API_CONFIG`, letting a user patch
22
+ individual values (for example a rotated host or client ID) without waiting for a new release.
23
+
24
+ :meta hide-value:
25
+ """
26
+
27
+ DEFAULT_API_CONFIG: APIConfig = {
28
+ 'application_id': 'BFE8C5ED-D687-4C19-A5DD-F92CDFC4503A',
29
+ 'user_agent': 'okhttp/4.12.0',
30
+ 'profile_groups_default': ('names,address,phoneNumbers,emails,country,languages,'
31
+ 'unitsOfMeasure,namesExtensions'),
32
+ 'hosts': {
33
+ 'foundational': 'https://api.foundational.ford.com',
34
+ 'login': 'https://login.ford.com',
35
+ 'tmc': 'https://api.autonomic.ai',
36
+ 'tmc_accounts': 'https://accounts.autonomic.ai',
37
+ 'vehicle': 'https://api.vehicle.ford.com'
38
+ },
39
+ 'auth': {
40
+ 'b2c': {
41
+ 'client_id': '09852200-05fd-41f6-8c21-d36d3497dc64',
42
+ 'policy_template': 'B2C_1A_SignInSignUp_{locale}',
43
+ 'redirect_uri': 'fordapp://userauthorized',
44
+ 'tenant_id': '4566605f-43a7-400a-946e-89cc9fdb0bd7'
45
+ },
46
+ 'tmc': {
47
+ 'client_id': 'fordpass-prod'
48
+ }
49
+ },
50
+ 'roadside': {
51
+ 'x_source': {
52
+ 'ford': 'FORD',
53
+ 'lincoln': 'LINCOLN'
54
+ }
55
+ }
56
+ }
57
+ """
58
+ Built-in FordPass API constants captured from the official mobile app.
59
+
60
+ These serve as the default bundle when :data:`API_CONFIG_FILE` is absent.
61
+
62
+ :meta hide-value:
63
+ """
64
+
65
+
66
+ def _merge_into(base: dict[str, Any], override: Mapping[str, Any]) -> None:
67
+ """
68
+ Recursively overlay ``override`` onto ``base`` in place.
69
+
70
+ Nested mappings are merged key by key; any other value (scalar, list, ...) replaces the value in
71
+ ``base`` wholesale.
72
+
73
+ Parameters
74
+ ----------
75
+ base : dict[str, Any]
76
+ The mapping to mutate. Typically a deep copy of :data:`DEFAULT_API_CONFIG`.
77
+ override : Mapping[str, Any]
78
+ The values to layer on top, such as a parsed override file.
79
+ """
80
+ for key, value in override.items():
81
+ existing = base.get(key)
82
+ if isinstance(existing, dict) and isinstance(value, Mapping):
83
+ _merge_into(existing, value)
84
+ else:
85
+ base[key] = value
86
+
87
+
88
+ @functools.cache
89
+ def load_api_config() -> APIConfig:
90
+ """
91
+ Return the FordPass API constants, merging any override file over the defaults.
92
+
93
+ The result starts from a copy of :data:`DEFAULT_API_CONFIG`. When :data:`API_CONFIG_FILE`
94
+ exists, its parsed contents are deep-merged on top, so an override may patch as few or as many
95
+ values as it likes.
96
+
97
+ Returns
98
+ -------
99
+ APIConfig
100
+ The effective constants bundle.
101
+ """
102
+ merged = cast('dict[str, Any]', copy.deepcopy(DEFAULT_API_CONFIG))
103
+ if API_CONFIG_FILE.exists():
104
+ _merge_into(merged, tomlkit.loads(API_CONFIG_FILE.read_text()).unwrap())
105
+ return cast('APIConfig', merged)