feat(vehicle): add support for LeapMotor API#29666
Draft
syphernl wants to merge 10 commits into
Draft
Conversation
- Remove EnsureAuth (dead code, had TOCTOU race) - Make addAuthHeaders void (return value was always ignored) - Drop Python-style inline comments in deriveP12Password - Collapse SM4 section divider to single comment line
ngehrsitz
reviewed
May 12, 2026
- Rename AppCert/AppKey → auto-download app certs from markoceri/leapmotor-certs
(removes file path requirement; certs fetched in parallel via errgroup)
- Replace custom SM4 impl with github.com/emmansun/gmsm (key recovered from
APK round key schedule); cipher block initialised once at package init
- Replace manual JWT parsing with golang-jwt/jwt in deriveSessionDeviceID
- Stable deviceID: SHA256(email)[:16] replaces per-restart random bytes
- NewIdentity accepts PEM bytes instead of file paths
- apiPost uses request.Helper.DoBody (adds HTTP status code checking)
- Add postAndParse[T] helper combining POST + envelope decode
- Add VehicleClimater, VehiclePosition, SocLimiter interfaces
- Add templates/definition/vehicle/leapmotor.yaml for UI discovery
- Use hex.EncodeToString instead of fmt.Sprintf("%x")
ngehrsitz
reviewed
May 15, 2026
Comment on lines
+274
to
+279
| acctCert, err := loadAccountCert(p12Bytes, pwd) | ||
| if err != nil { | ||
| return fmt.Errorf("load account cert (derived password): %w", err) | ||
| } | ||
| id.acctClient = newMTLSClient(&acctCert) | ||
| return nil |
Contributor
There was a problem hiding this comment.
We should also persist the client certificate so that we can immediately try to use that and only fallback to the complex login flow when it doesn´t work or is missing.
- Cache app certs in DB; fetch from GitHub only when missing or on TLS
failure (avoids unauthenticated rate-limit hits on every startup)
- Add TryRestore(): load persisted session (token, acct cert) from DB,
skip full login when session is still valid; login() persists session
after each successful auth
- SinglePhaseLeapmotor wrapper reports Phases()=1 for T03
- extractSessionDeviceID: typed usernameClaims struct, return *string
(no fallback param); fix len check >= 3 instead of >= 4
- Merge addAuthHeaders into buildSignedHeaders (userID/token params)
- maps.Copy + slices.Collect(maps.Keys) + slices.Sort in buildSignedHeaders
- hex.EncodeToString(mac.Sum(nil)) instead of fmt.Sprintf("%x", ...)
- Replace init() block with package-level var for p12SM4Block
- slices.DeleteFunc for VIN filtering in Vehicles()
- Add unit tests for extractSessionDeviceID, deriveSignKey,
p12MemoryEncode, deriveP12Password
Implements api.ChargeController via REMOTE_CTL_CHARGE_START/STOP (cmdId=193) when a vehicle PIN is configured. PIN is optional — omitting it preserves existing read-only behaviour. New config field: `pin` (redacted in logs). - Identity: AES-128-CBC PIN encryption, cert sync, HasPin/EncryptedPin - API: ChargeToggle — PIN verify + remote/ctl two-step flow - LeapmotorWithControl / SinglePhaseLeapmotorWithControl types expose ChargeEnable only when PIN is present
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Adds Leapmotor cloud API support (same API the official app uses). The API is unofficial but community-documented:
App certs download automatically from markoceri/leapmotor-certs on startup, no files to provide.
Supported data
SoC, charge state, range, odometer, finish time, climate state, GPS position, SoC limit.
Caveats
Status
Not tested on a real car yet. Draft until someone validates it on a T03, B10, or C10.Tested by @ngehrsitz on a T03: #29666 (review)
References