feat: add VehicleProfile and capability properties for EU API - #1157
feat: add VehicleProfile and capability properties for EU API#1157blka wants to merge 2 commits into
Conversation
aa84498 to
d9c97e5
Compare
|
Same comment as the one from #1158 applies, what is the use case for this? Let's not add extra API calls if there are no benefits to end users. |
d9c97e5 to
fccd015
Compare
|
Thanks @Lekensteyn — restructured to address the use-case question and the extra-call concern. Use cases the capability flags enable (kia_uvo consumer planned for a near-future follow-up PR):
Extra API call: profile is now fetched inside Surface reduction: Architecture: shared SPA logic lives in Live-verified against the EU API (Hyundai, EU account; identifiers redacted): All 13 capability properties return coherent values; profile fetch worked end-to-end inside Happy to adjust if the capability set (13) is too broad — a fallback would be to keep only the ones with an immediate use case (horn, sunroof, heaters, defrost, lamps) and defer |
fccd015 to
5930c06
Compare
|
@Lekensteyn can you check pls? |
5930c06 to
a472f62
Compare
9af9c7a to
6b68153
Compare
- VehicleProfile dataclass (~50 fields) mapping EU /api/v1/spa/vehicles/{id}/profile
- 13 capability properties on Vehicle reading from Vehicle.profile (HA getattr pattern, None when no profile)
- str_or_none utility for int-or-string option coercion
- supports_vehicle_profile flag on ApiImpl (False by default), True on KiaUvoApiEU
- _fetch_vehicle_profiles + _map_vehicle_profile in ApiImplType1, piggybacked on get_vehicles (login only, not per poll)
- Graceful degradation: profile fetch failure leaves vehicle.profile = None
- 21 unit tests + EU profile fixture
Non-supporting regions (CA, USA, BR) make zero extra calls. AU/IN/CN stay off until their /profile schema is verified.
6b68153 to
31e49fa
Compare
|
@cdnninja — could you take a look when you have a moment? This is scoped as a read-only foundation: Kept it focused (no consumers wired here on purpose). Happy to adjust scope or naming. |
| if profile_data: | ||
| vehicle.profile = self._map_vehicle_profile(profile_data[0]) | ||
| except Exception: | ||
| _LOGGER.debug( |
There was a problem hiding this comment.
We should plan for this to work, if widespread failures occur something is wrong and we should take care of it. Maybe up this to warning?
| navi_applied: bool | None = None | ||
| web_manual_url: str | None = None | ||
|
|
||
| # option (raw API values) |
There was a problem hiding this comment.
Do we know what these are? It isn't clear from the title for some of them. I would think many of these should be bool. They will need a way to be normalized for all regions.
There was a problem hiding this comment.
On a similar thought the logic for supported looks to focus on a value so seems these are known in some way but hard codes vehicle to a region.
Per PR Hyundai-Kia-Connect#1157 review: profile fetch failures should be visible at warning level since widespread failures indicate a real problem worth investigating. Add exc_info=True so the traceback is captured. The vehicle still degrades gracefully (profile stays None, capability properties return None) — only the log level changes.
Summary
VehicleProfiledataclass (~70 fields) mapping the EU/api/v1/spa/vehicles/{id}/profileendpoint response (basic, device, option, serviceOption, batteryType, detailInfo, dtcCategory sections + top-levelappModedispatch field)Vehiclethat read fromVehicle.profilefor HAgetattrcompatibility — returnNonewhen profile is unavailable or the specific option flag is absent (unknown),boolwhen presentstr_or_noneutility for int-or-string option-value coercion (API returns some option fields as ints, others as strings; capability props compare against string values)supports_vehicle_profileflag onApiImpl(Falseby default), setTrueonly onKiaUvoApiEU_fetch_vehicle_profiles+_map_vehicle_profileinApiImplType1, piggybacked onto the existing vehicle-list call insideget_vehicles(login only, not per poll cycle), gated onsupports_vehicle_profile. Usesself.session.get(ApiImplSession, consistent with feat: add ApiImplSession with timeout and connection pooling #1160)vehicle.profile = None— no crash, no extra API calls on subsequent polls/profileschema is verifiedappMode=EV5)Profile request frequency
The
/profileGET is 1 request per vehicle, only at integration startup (first poll, whenvehicle_manager.vehiclesis empty →initialize_vehicles→get_vehicles), on HA restart, config-entry reload, or re-auth. It is not called on the poll cycle (update_all_vehicles_with_cached_state), on force-refresh, or on token refresh (EUrefresh_vehiclesis a no-op). So a 1-vehicle account makes exactly 1 extra GET at startup.Capability properties (29)
From vehicle options/status (13):
steering_wheel_heater_supported,side_mirror_heater_supported,rear_window_heater_supported,front_window_heating_supported,sunroof_supported,digital_key_supported,air_purifier_supported,remote_heat_control_supported,ignition_control_supported,horn_light_supported,light_only_supported,ev_alarm_supported,is_left_hand_driveFrom
option/serviceOptionflags (16, added from volunteer /profile dumps in kia_uvo discussion #1764 — Kia EV6 CCS2/ccNC + 2021 e-Niro CCSP):svm_supported(Surround View Monitor / 360°),v2l_supported(Vehicle-to-Load),v2x_supported(Vehicle-to-Everything),v2g_supported(Vehicle-to-Grid),frunk_supported,climate_control_supported(clmtCtrl),battery_preconditioning_supported,digital_side_mirror_supported(cms / Camera Monitoring System),wireless_charging_supported,remote_front_window_heat_supported,window_safety_supported,charge_port_door_supported,charging_current_control_supported,v2l_soc_set_supported(V2L discharge SoC limit),window_control_supported,remote_light_control_supportedThese flags are
Nonewhen the profile or the specific option field is absent (some fields are reported only on certain vehicle generations — e.g.V2GOption/wirelessChargingOption/windowControlOptionon older CCSP,V2LOption/frunkOption/batteryPreconditioningOptionon newer ccNC), so consumers can distinguish "unknown" from "not supported".Use cases (capability flags enable future kia_uvo gating)
start_hazard_lights/start_hazard_lights_and_hornunconditionally; CA/USA raiseNotImplementedError→UnsupportedControlErrorat action time.horn_light_supportedlets kia_uvo hide the buttons where the endpoint does not exist.sunroof_is_openfor EU/AU today;sunroof_supported+ status population fixes this.getattr(vehicle, attr, None) is not None, which proxies "data present in last poll", not "vehicle supports". Entities flap after partial polls / force-refresh when a value is momentarilyNone. A stable flag from/profilestops the flapping.strgWhlHeating/sideRearMirrorHeating/windshieldFrontDefogStateunconditionally; capability flags let the library send them only when supported.battery_preconditioning_supported/v2l_supported/charge_port_door_supported/charging_current_control_supportedenable kia_uvo to expose or hide EV-specific entities per vehicle instead of guessing from data presence.Per @Lekensteyn's concern on #1158: profile is fetched inside
get_vehicles(piggybacked on the existing vehicle-list call at login), not per poll cycle, and only whensupports_vehicle_profileisTrue.UserAccount(#1158) is dropped — no consumer, #1158 closed.Architecture
Shared SPA logic lives in
ApiImplType1(precedent: ccs2, climate, drvSeatLoc). The EU mapping is consolidated into Type1 with asupports_vehicle_profileflag (precedent:supports_window_control), so AU/IN/CN can adopt it by flipping the flag once their/profileschema is verified — no code duplication. Coexists withsupports_valet_modefrom #1207.appModeis exposed asVehicleProfile.app_modefor the scheduled-charge/climate endpoint dispatch (flat/ccs2/reservation/{charge,hvac}forEV5vs combined/chargehvacfor older vehicles — follow-up scheduled-charging PR).Test plan
pytest tests/— 434 passed, 11 skipped (10 snapshots)ruff check .+ruff format --check— cleanpre-commit run --all-files— all hooks pass incl. mypyappModeand the 16 option flags confirmed present on EV6 (ccs2/ccNC), absent on 2021 e-Niro (CCSP)vehicle.profile = Nonewithout crashingDeferred to separate PRs
data_timezoneper-vehicle)