fix(EU): correct CCSP Stamp so remote commands work across Europe - #47
Open
RJvdBurg wants to merge 1 commit into
Open
fix(EU): correct CCSP Stamp so remote commands work across Europe#47RJvdBurg wants to merge 1 commit into
RJvdBurg wants to merge 1 commit into
Conversation
…tus refresh
Ports the proven behaviour of Home Assistant's hyundai_kia_connect_api to
the European Hyundai/Kia clients. Remote actions previously failed across
Europe (e.g. the Netherlands) with HTTP 403; reads worked but every control
command was rejected.
- Stamp: generate the CCSP `Stamp` as base64(CFB XOR "<appId>:<unixSeconds>")
instead of HMAC-SHA256 over an ISO8601 timestamp. The HMAC form was
tolerated on read endpoints but rejected with 403 on control endpoints,
which is what broke lock/unlock/climate/charge across the EU. Verified
byte-identical to hyundai_kia_connect_api `_get_stamp`. Drops the now-unused
CryptoKit imports.
- Errors: decode the CCSP `retCode:"F"` / `resCode` envelope into typed,
user-facing APIErrors (duplicate request, timeout, rate limit, etc.) instead
of surfacing a bare "HTTP 400: bad request". Mirrors
`_check_response_for_errors`. Guarded on the CCSP envelope so US/CA/CN are
unaffected.
- Climate: derive `drvSeatLoc` from the vehicle's distance unit ("L" for
km-based LHD markets, "R" for mile-based UK/IE) and swap driver/passenger
seat channels for RHD, instead of hardcoding "R". Also derive
sideRearMirrorHeating from the heating level. Matches `start_climate`.
- Status: honour the `cached` flag on EU CCS2 vehicles. A non-cached refresh
now wakes the car (GET /ccs2/carstatus), waits ~20s, then reads /latest, so
a just-sent command is reflected instead of a stale snapshot. Ports
`_force_refresh_vehicle_state_ccs2`. bbcli's status action now requests a
fresh read.
Adds CCSPResponseErrorTests. swift build clean; 309 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Problem
Remote commands failed for European Hyundai/Kia vehicles: login and status reads worked, but every control command (lock/unlock, climate, charge) came back HTTP 403 Forbidden. Reported in #62 (Ioniq 5) and #68 (Santa Fe, Netherlands), where the community specifically asked how Home Assistant sends commands to the EU API.
Root cause: the
Stampheader was generated with HMAC-SHA256 over an ISO8601 timestamp. That isn't the CCSP scheme — the EU servers tolerate it on read endpoints but reject it with 403 on control endpoints. Verified againsthyundai_kia_connect_api(Home Assistant), which is the reference implementation for this API.Changes (all ported from
hyundai_kia_connect_api)Stampgeneration — base64(CFBXOR"<appId>:<unixSeconds>"), XOR truncated to the shorter operand, instead of HMAC-SHA256/ISO8601. TheauthCfbsecret already in the repo is byte-identical to HA'sCFB; only the algorithm was wrong. Output verified byte-for-byte against HA's_get_stamp. Removes the now-unusedCryptoKitimports. This is the fix for the 403.Control-error decoding — the CCSP
retCode:"F"/resCodeenvelope is now translated into typedAPIErrors (duplicate request4004, timeout4081/9999, unavailable5031, rate-limited5091, unsupported4005, bad deviceId4002, auth7501) instead of surfacing a bareHTTP 400: bad request. Mirrors_check_response_for_errors. Guarded on the CCSP envelope, so US/CA/CN clients are unaffected.CCS2 climate payload —
drvSeatLocis now derived from the vehicle's distance unit ("L"for km-based LHD markets,"R"for mile-based UK/IE) and the driver/passenger seat channels swap for RHD, instead of being hardcoded to"R".sideRearMirrorHeatingis derived from the heating level. Matchesstart_climate/ #1192.Live status refresh — the
cachedflag is now honoured on EU CCS2 vehicles. A non-cached refresh wakes the car (GET /ccs2/carstatus), waits ~20s, then reads/latest, so a just-sent command is reflected instead of a stale cached snapshot. Ports_force_refresh_vehicle_state_ccs2/ #1184.bbcli's status action now requests a fresh read.Testing
swift buildclean,swift testgreen (309 tests, incl. newCCSPResponseErrorTests).resCodeerrors surface clearly; force-refresh returns accurate live state.Note
Remote climate on that specific hybrid Santa Fe does not execute even though the API accepts the command (
retCode:"S") — confirmed disabled in the official MyHyundai app for the vehicle, i.e. a manufacturer/market capability limit, not a client issue. Related to the open, unsolved ICE/PHEV remote-start question in #1224. All four changes here are independent of that limitation.