feat(vehicle): add support for LeapMotor API#29666
Draft
syphernl wants to merge 5 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
Comment on lines
+235
to
+238
| // newMTLSClient creates an http.Client with optional client cert and TLS verification disabled. | ||
| // Leapmotor's API servers use self-signed certificates. | ||
| func newMTLSClient(cert *tls.Certificate) *http.Client { | ||
| tlsCfg := &tls.Config{InsecureSkipVerify: true} //nolint:gosec |
| } | ||
| return float64(*res.TotalMileage), nil | ||
| } | ||
|
|
Contributor
There was a problem hiding this comment.
Looking at https://github.com/markoceri/leapmotor-api we can also implement VehicleClimater,VehiclePosition,SocLimiter and even PhaseDescriber for the 1P only models like T03
| } | ||
|
|
||
| func init() { | ||
| registry.Add("leapmotor", NewLeapmotorFromConfig) |
Contributor
There was a problem hiding this comment.
You need templates/definition/vehicle/leapmotor.yaml otherwise it won´t be shown in the UI
Comment on lines
+59
to
+73
| func apiPost(client *http.Client, fullURL string, headers map[string]string, body string) ([]byte, error) { | ||
| req, err := http.NewRequest(http.MethodPost, fullURL, strings.NewReader(body)) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| for k, v := range headers { | ||
| req.Header.Set(k, v) | ||
| } | ||
| resp, err := client.Do(req) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| defer resp.Body.Close() | ||
| return io.ReadAll(resp.Body) | ||
| } |
Contributor
There was a problem hiding this comment.
This could be substituted with request.DoBody()
Comment on lines
+75
to
+86
| // parseEnvelope decodes the API envelope, returning Data or an error for non-zero codes. | ||
| func parseEnvelope[T any](body []byte) (T, error) { | ||
| var res apiEnvelope[T] | ||
| var zero T | ||
| if err := json.Unmarshal(body, &res); err != nil { | ||
| return zero, err | ||
| } | ||
| if res.Code != 0 { | ||
| return zero, fmt.Errorf("api %d: %s", res.Code, res.Message) | ||
| } | ||
| return res.Data, nil | ||
| } |
Contributor
There was a problem hiding this comment.
This is always used after apiPost() or do() which is mostly the same thing. I would either combine them, or even better reuse the shared functionality for decoding JSON.
- 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")
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.
Docs
evcc-io/docs#1049
References