Metadata-Version: 2.4
Name: py-uconnect
Version: 0.4.0
Summary: Python API Client for FCA/Stellantis cars
Home-page: https://github.com/hass-uconnect/py-uconnect
Author: Olga Novgorodova
Author-email: olga@novg.net
License: Apache license
Keywords: fiat,jeep,dodge,ram,alfa,romeo,maserati,chrysler,api,cloud
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Natural Language :: English
Classifier: Programming Language :: Python :: 3.10
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: boto3>=1.35.96
Requires-Dist: requests>=2.32.3
Requires-Dist: requests-auth-aws-sigv4>=0.7
Requires-Dist: dataclasses_json>=0.6.7
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# Python client for accessing FCA/Stellantis cars cloud API

## Installation

`pip3 install py-uconnect`

## Usage

```python
from py_uconnect import brands, Client

# Create client
client = Client('foo@bar.com', 'very_secret', pin='1234', brand=brands.FIAT_EU)
# Fetch the vehicle data into cache
client.refresh()

# List vehicles
vehicles = client.get_vehicles()
for vehicle in vehicles.values():
    print(vehicle.to_json(indent=2))
```

This would emit something similar to:
```json
{
  "vin": "XXXXXXXXXXXXXXXXXXXX",
  "nickname": "500e",
  "make": "FIAT",
  "model": "Neuer 500",
  "year": 2023,
  "region": "EMEA",
  "sdp": null,
  "image_url": "https://example.com/vehicle/image.png",
  "fuel_type": "E",
  "ignition_on": false,
  "trunk_locked": true,
  "odometer": 1841,
  "odometer_unit": "km",
  "days_to_service": 325,
  "distance_to_service": 13159.0,
  "distance_to_service_unit": "km",
  "distance_to_empty": 134,
  "distance_to_empty_unit": "km",
  "battery_voltage": 14.875,
  "battery_state_of_charge": "normal",
  "oil_level": null,
  "fuel_low": false,
  "fuel_amount": null,
  "plugged_in": false,
  "ev_running": false,
  "charging": false,
  "charging_level": 0,
  "charging_level_preference": 5,
  "state_of_charge": 63,
  "time_to_fully_charge_l3": 41,
  "time_to_fully_charge_l2": 96,
  "time_to_fully_charge_l1": null,
  "ev_head_seat": null,
  "ev_cabin_cond": null,
  "wheel_front_left_pressure": null,
  "wheel_front_left_pressure_unit": "kPa",
  "wheel_front_left_pressure_warning": false,
  "wheel_front_right_pressure": null,
  "wheel_front_right_pressure_unit": "kPa",
  "wheel_front_right_pressure_warning": false,
  "wheel_rear_left_pressure": null,
  "wheel_rear_left_pressure_unit": "kPa",
  "wheel_rear_left_pressure_warning": false,
  "wheel_rear_right_pressure": null,
  "wheel_rear_right_pressure_unit": "kPa",
  "wheel_rear_right_pressure_warning": false,
  "door_driver_locked": true,
  "door_passenger_locked": true,
  "door_rear_left_locked": true,
  "door_rear_right_locked": true,
  "window_driver_closed": true,
  "window_passenger_closed": true,
  "location": {
    "longitude": 1.580266952514648,
    "latitude": 1.36115264892578,
    "altitude": 0,
    "bearing": 0,
    "is_approximate": false,
    "updated": 1738660203.634
  },
  "supported_commands": [
    "RDL",
    "RDU",
    "VF",
    "ROLIGHTS",
    "CNOW",
    "DEEPREFRESH",
    "ROPRECOND",
    "ROTRUNKUNLOCK",
    "ROPRECOND_OFF"
  ],
  "enabled_services": [
    "RDL",
    "RDU",
    "VF",
    "ROLIGHTS",
    "CNOW",
    "DEEPREFRESH",
    "ROPRECOND",
    "ROTRUNKUNLOCK",
    "ROPRECOND_OFF",
    "SVLA",
    "BCALL",
    "ECALL"
  ]
}
```

## Additional API methods

```python
# Vehicle health report
report = client.get_vehicle_health_report(vin)

# Maintenance history
history = client.get_maintenance_history(vin)

# Eco-coaching trip data
last_trip = client.get_eco_coaching_last_trip(vin)
trips = client.get_eco_coaching_trips(vin)

# Vehicle image (dedicated endpoint)
image = client.get_vehicle_image(vin)

# EV charge schedules
schedules = client.get_charge_schedules(vin)
client.set_charge_schedule(vin, schedule)

# Remote operation status (check if a command succeeded)
status = client.get_remote_operation_status(vin, correlation_id)

# Stolen vehicle locator status (SiriusXM Guardian / SVLA)
svla = client.get_stolen_vehicle_status(vin)

# Vehicle subscription status
subscription = client.get_vehicle_subscription(vin)

# Set vehicle nickname
client.set_vehicle_nickname(vin, "My Car")

# Trigger a fresh location update (returns correlation ID)
correlation_id = client.update_location(vin)
```

## Service Delivery Platform (SDP)

NAFTA vehicles report a `sdp` field indicating the connected services provider:
- `"SXM"` - SiriusXM Guardian
- `"SPRINT"` - Uconnect Access (Sprint/T-Mobile)
- `null` - EMEA/LATAM/IAP regions (no SDP distinction)

The `enabled_services` field lists all active services on the vehicle, including
non-command services like `SVLA` (Stolen Vehicle Locator), `BCALL`, `ECALL`, etc.

## SiriusXM Guardian vehicles

Some US-market vehicles use SiriusXM Guardian as their connected services provider
instead of the standard Uconnect cellular service. These vehicles may not appear in
the API if the account has not been properly linked.

Analysis of the official Stellantis mobile apps (Ram NAFTA, Chrysler NAFTA, Wagoneer
NAFTA) shows that:

- There are **no separate API endpoints** for SXM Guardian vehicles. All vehicles use
  `channels.sdpr-02.fcagcv.com` regardless of SDP type.
- The `sdp` field only affects UI presentation (subscription messages, branding).
- The apps contain a **legacy Mopar login fallback**: when Gigya login fails for a
  Mopar-only account, the app POSTs to `api.extra.fcagroup.com` which triggers a
  server-side account migration to Gigya, then retries the standard login.

This suggests SXM Guardian vehicles should work once the account is migrated to Gigya.
However, we cannot fully verify this without a real SXM Guardian account because some
configuration values in the APK are encrypted.

If your SiriusXM Guardian vehicle does not appear:

1. Install the official app for your brand (Jeep, Ram, Chrysler, Dodge, etc.)
2. Log in with your Mopar/SXM Guardian credentials
3. If the app prompts you to link or migrate your account, complete the process
4. Verify your vehicle is visible and functional in the official app
5. Use the same credentials with this library

If your vehicle still does not appear after completing these steps, please open an
issue with your vehicle year, make, model, and whether it shows in the official app.
