feat(assets): add Model Y Juniper Performance and Premium support (#15)

- Add 6 Performance images with 21" Überturbine wheels
- Add 15 Standard/Premium images with 18"/19"/20" wheels
- Support 6 colors for Premium: PPSW, PN01, PX02, PN00, PR01, PPSB
- Detect Performance via trim_badging (P74D) or 21" wheels
- Detect Premium via 19" Crossflow or 20" Helix wheels

Fixes #1
This commit is contained in:
Davide Ferrari
2026-01-05 19:08:30 +01:00
committed by GitHub
parent a44f808861
commit 7f6218e5c0
19 changed files with 132 additions and 42 deletions
+3
View File
@@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- **Model Y Juniper Performance**: Support for P74D trim with 21" Überturbine wheels and red brake calipers
- **Model Y Juniper Premium**: Support for Premium (74/74D trim) with 19" Crossflow and 20" Helix 2.0 wheels in 6 colors (PPSW, PN01, PX02, PN00, PR01, PPSB)
- **Model Y Juniper Trim Detection**: Proper variant detection based on trim_badging (50=Standard, 74/74D=Premium, P74D=Performance)
- **Stats for Nerds**: Tap the car image on Dashboard to access advanced statistics
- Quick Stats: Total drives/charges, distance, energy, efficiency, top speed
- Records: Longest drive, fastest drive, most efficient drive, biggest charge, busiest day
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

@@ -12,7 +12,13 @@ package com.matedroid.domain.model
* - Legacy Model 3 (pre-2024): m3_{color}_{wheel}.png
* - Highland Model 3 (2024+): m3h_{color}_{wheel}.png or m3hp_{color}_{wheel}.png
* - Legacy Model Y (pre-2025): my_{color}_{wheel}.png
* - Juniper Model Y (2025+): myj_{color}_{wheel}.png
* - Juniper Model Y (2025+): myj_{color}_{wheel}.png (Standard/Premium)
* - Juniper Model Y Performance (2025+): myjp_{color}_{wheel}.png (has red calipers)
*
* Juniper Model Y trim detection via trim_badging:
* - "50" = Standard Range (18" Photon wheels)
* - "74", "74D" = Long Range/Premium (19" Crossflow wheels)
* - "P74D" = Performance (21" Überturbine wheels, red calipers)
*/
object CarImageResolver {
@@ -30,7 +36,7 @@ object CarImageResolver {
"white" to "PPSW",
"pearlwhite" to "PPSW",
"pearlwhitemulticoat" to "PPSW",
"deepblue" to "PPSB",
"deepblue" to "PPSB", // Legacy deep blue
"deepbluemetallic" to "PPSB",
"blue" to "PPSB",
"red" to "PPMR",
@@ -42,6 +48,7 @@ object CarImageResolver {
"midnightcherryred" to "PR00",
"ultrared" to "PR01",
"blackdiamond" to "PX02"
// Note: PB02 (Juniper Deep Blue) is handled via fallback - same TeslamateAPI name as PPSB
)
// Colors only available on Highland/Juniper
@@ -52,7 +59,7 @@ object CarImageResolver {
private val HIGHLAND_M3_WHEEL_TYPES = setOf("photon18", "glider18", "nova18", "nova19", "helix19", "w38a")
// Wheel types only available on Juniper Model Y (normalized, lowercase)
private val JUNIPER_MY_WHEEL_TYPES = setOf("photon18", "wy18p", "crossflow19", "wy19p")
private val JUNIPER_MY_WHEEL_TYPES = setOf("photon18", "wy18p", "crossflow19", "wy19p", "helix20", "wy20a")
// Legacy Model 3 valid colors
private val LEGACY_M3_COLORS = setOf("PBSB", "PMNG", "PMSS", "PPSW", "PPSB", "PPMR", "PMBL")
@@ -63,8 +70,12 @@ object CarImageResolver {
// Legacy Model Y valid colors
private val LEGACY_MY_COLORS = setOf("PBSB", "PMNG", "PPSW", "PPSB", "PPMR")
// Juniper Model Y valid colors
private val JUNIPER_MY_COLORS = setOf("PPSW", "PN01", "PX02")
// Juniper Model Y valid colors (Standard/Premium)
// Note: PN00/PR01/PPSB only available with Premium (MTY60) 19"/20" wheels
private val JUNIPER_MY_COLORS = setOf("PPSW", "PN01", "PX02", "PN00", "PR01", "PPSB")
// Juniper Model Y Performance valid colors (all 6 colors)
private val JUNIPER_MY_PERF_COLORS = setOf("PPSW", "PN01", "PX02", "PB02", "PN00", "PR01")
// Wheel code mappings per model variant
// Keys are patterns that match the start of the TeslamateAPI wheel type
@@ -118,14 +129,22 @@ object CarImageResolver {
"18" to "WY18B"
)
// Juniper Model Y wheels
// Juniper Model Y wheels (Standard/Premium)
private val WHEEL_PATTERNS_MYJ = listOf(
"helix20" to "WY20A",
"crossflow19" to "WY19P",
"photon18" to "WY18P",
"20" to "WY20A",
"19" to "WY19P",
"18" to "WY18P"
)
// Juniper Model Y Performance wheels
private val WHEEL_PATTERNS_MYJP = listOf(
"uberturbine21" to "WY21A",
"21" to "WY21A"
)
// Model S wheels
private val WHEEL_PATTERNS_MS = listOf(
"tempest19" to "WT19",
@@ -145,6 +164,7 @@ object CarImageResolver {
"m3hp" to "W30P",
"my" to "WY19B",
"myj" to "WY18P",
"myjp" to "WY21A",
"ms" to "WT19",
"mx" to "WX20"
)
@@ -156,6 +176,7 @@ object CarImageResolver {
"m3hp" to "PPSW",
"my" to "PPSW",
"myj" to "PPSW",
"myjp" to "PPSW",
"ms" to "PPSW",
"mx" to "PPSW"
)
@@ -210,7 +231,7 @@ object CarImageResolver {
fun getScaleFactorForVariant(modelVariant: String): Float {
return when (modelVariant) {
"m3h", "m3hp" -> 1.35f // Highland Model 3 renders smaller
"myj" -> 1.25f // Juniper Model Y renders smaller
"myj", "myjp" -> 1.25f // Juniper Model Y renders smaller
"mx" -> 1.4f // Model X renders smaller
else -> 1.0f // Legacy models render at full size
}
@@ -271,6 +292,11 @@ object CarImageResolver {
* 1. If color is a new Highland/Juniper-only color (PN00, PN01, PR01, PX02), use Highland/Juniper
* 2. If wheel type is a Highland/Juniper-only wheel (Photon18, Glider18, etc.), use Highland/Juniper
* 3. Otherwise, assume legacy
*
* Trim badging for Juniper Model Y:
* - "50" = Standard Range (18" Photon wheels)
* - "74", "74D" = Long Range/Premium (19" Crossflow wheels)
* - "P74D" = Performance (21" Überturbine wheels, red calipers)
*/
private fun determineModelVariant(
model: String?,
@@ -288,10 +314,14 @@ object CarImageResolver {
val isHighlandM3Wheel = normalizedWheel != null && HIGHLAND_M3_WHEEL_TYPES.any { normalizedWheel.startsWith(it) }
val isJuniperMYWheel = normalizedWheel != null && JUNIPER_MY_WHEEL_TYPES.any { normalizedWheel.startsWith(it) }
// Check for Performance trim
// Check for Performance trim (P prefix like "P74D")
val isPerformance = trimBadging?.uppercase()?.startsWith("P") == true ||
trimBadging?.lowercase()?.contains("performance") == true
// Check for 21" Überturbine wheels (Performance-only on Juniper)
val isJuniperPerfWheel = normalizedWheel?.startsWith("uberturbine21") == true ||
normalizedWheel?.startsWith("21") == true
return when (baseModel) {
"3" -> when {
(isHighlandJuniperColor || isHighlandM3Wheel) && isPerformance -> "m3hp"
@@ -299,6 +329,9 @@ object CarImageResolver {
else -> "m3"
}
"Y" -> when {
// Juniper Performance: P74D trim or 21" wheels
(isHighlandJuniperColor || isJuniperMYWheel || isJuniperPerfWheel) && (isPerformance || isJuniperPerfWheel) -> "myjp"
// Juniper Standard/Premium: non-P trim with Juniper colors/wheels
isHighlandJuniperColor || isJuniperMYWheel -> "myj"
else -> "my"
}
@@ -318,6 +351,7 @@ object CarImageResolver {
"m3h", "m3hp" -> HIGHLAND_M3_COLORS
"my" -> LEGACY_MY_COLORS
"myj" -> JUNIPER_MY_COLORS
"myjp" -> JUNIPER_MY_PERF_COLORS
"ms", "mx" -> MODEL_SX_COLORS
else -> LEGACY_M3_COLORS
}
@@ -346,6 +380,7 @@ object CarImageResolver {
"m3hp" -> WHEEL_PATTERNS_M3HP
"my" -> WHEEL_PATTERNS_MY
"myj" -> WHEEL_PATTERNS_MYJ
"myjp" -> WHEEL_PATTERNS_MYJP
"ms" -> WHEEL_PATTERNS_MS
"mx" -> WHEEL_PATTERNS_MX
else -> WHEEL_PATTERNS_M3
+55 -31
View File
@@ -76,7 +76,8 @@ https://static-assets.tesla.com/configurator/compositor?context=design_studio_2&
| Highland Model 3 | 2024+ | New | `m3h` |
| Highland Model 3 Performance | 2024+ Perf | New | `m3hp` |
| Legacy Model Y | Pre-2025 | Old | `my` |
| Juniper Model Y | 2025+ | New | `myj` |
| Juniper Model Y | 2025+ Standard/Premium | New | `myj` |
| Juniper Model Y Performance | 2025+ Performance | New | `myjp` |
| Model S | All | Old | `ms` |
| Model X | All | Old | `mx` |
@@ -87,7 +88,24 @@ https://static-assets.tesla.com/configurator/compositor?context=design_studio_2&
| `MT369` | Model 3 Highland | Standard | `IPB2` |
| `MT370` | Model 3 Highland | Premium | `IPB3` |
| `MT371` | Model 3 Highland | Performance | `IPB4` |
| `MTY68` | Model Y Juniper | Standard | `IBB3` |
| `MTY68` | Model Y Juniper | Standard/Long Range | `IBB3` |
| `MTY52` | Model Y Juniper | Premium (19") | `IPB7` |
| `MTY60` | Model Y Juniper | Premium (20") | `IPB8` |
| `MTY53` | Model Y Juniper | Performance | `IPB10` |
**Note on Model Y Juniper compositor support:**
- `MTY68` works with `STUD_3QTR` view for 3 colors (PPSW, PN01, PX02) with 18"/19" wheels
- `MTY52` has limited support on `STUD_3QTR` - we use `MTY68` with 19" wheels instead
- `MTY60` works with `STUD_3QTR` view for 5 colors (PPSW, PN01, PX02, PN00, PR01) with 20" wheels
- `MTY53` works with `STUD_3QTR` view for all 6 colors with 21" wheels
### Model Y Juniper Trim Badging (from TeslamateAPI)
| Trim Badge | Variant | Default Wheels | Notes |
|------------|---------|----------------|-------|
| `50` | Standard Range | 18" Photon (WY18P) | |
| `74`, `74D` | Long Range/Premium | 19" Crossflow (WY19P) | |
| `P74D` | Performance | 21" Überturbine (WY21A) | Red brake calipers |
---
@@ -112,19 +130,20 @@ https://static-assets.tesla.com/configurator/compositor?context=design_studio_2&
### Color Availability by Model Variant
| Color Code | Legacy M3 | Highland M3 | Legacy MY | Juniper MY |
|------------|-----------|-------------|-----------|------------|
| `PBSB` | ✅ | ✅ | ✅ | ❌ |
| `PMBL` | ✅ | ❌ | ❌ | ❌ |
| `PMNG` | ✅ | ❌ | ✅ | ❌ |
| `PMSS` | ✅ | ❌ | ❌ | ❌ |
| `PPSW` | ✅ | ✅ | ✅ | ✅ |
| `PPSB` | ✅ | ✅ | ✅ | ❌ |
| `PPMR` | ✅ | ❌ | ✅ | ❌ |
| `PN00` | ❌ | ✅ | ❌ | ❌ |
| `PN01` | ❌ | ✅ | ❌ | ✅ |
| `PR01` | ❌ | ✅ | ❌ | ❌ |
| `PX02` | ❌ | ✅ | ❌ | ✅ |
| Color Code | Legacy M3 | Highland M3 | Legacy MY | Juniper MY | Juniper MY Perf |
|------------|-----------|-------------|-----------|------------|-----------------|
| `PBSB` | ✅ | ✅ | ✅ | ❌ | ❌ |
| `PMBL` | ✅ | ❌ | ❌ | ❌ | ❌ |
| `PMNG` | ✅ | ❌ | ✅ | ❌ | ❌ |
| `PMSS` | ✅ | ❌ | ❌ | ❌ | ❌ |
| `PPSW` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `PPSB` | ✅ | ✅ | ✅ | ❌ | ❌ |
| `PPMR` | ✅ | ❌ | ✅ | ❌ | ❌ |
| `PN00` | ❌ | ✅ | ❌ | ❌ | ✅ |
| `PN01` | ❌ | ✅ | ❌ | ✅ | ✅ |
| `PR01` | ❌ | ✅ | ❌ | ❌ | ✅ |
| `PX02` | ❌ | ✅ | ❌ | ✅ | ✅ |
| `PB02` | ❌ | ❌ | ❌ | ❌ | ✅ |
---
@@ -144,26 +163,29 @@ https://static-assets.tesla.com/configurator/compositor?context=design_studio_2&
| `Photon18*` | `W38A` | `WY18P` | 18" Photon (Highland/Juniper) |
| `Nova19*`, `Helix19*` | `W38A`* | - | 19" Nova (Highland M3) - *fallback, not in compositor |
| `Crossflow19*` | - | `WY19P` | 19" Crossflow (Juniper MY) |
| `Helix20*` | - | `WY20A` | 20" Helix 2.0 (Juniper MY Premium) |
| `Glider18*`, `Nova18*` | `W38A` | - | 18" Glider/Nova (Highland M3) |
**Note**: TeslamateAPI may append suffixes like `CapKit`, `Cover`, etc. The mapping strips these.
### Wheel Availability by Model Variant
| Wheel Code | Legacy M3 | Highland M3 | Highland M3P | Legacy MY | Juniper MY |
|------------|-----------|-------------|--------------|-----------|------------|
| `W38B` | ✅ | ❌ | ❌ | - | - |
| `W39B` | ✅ | ❌ | ❌ | - | - |
| `W32P` | ✅ | ❌ | ❌ | - | - |
| `W38A` | ❌ | ✅ | ❌ | - | - |
| `W30P` | ❌ | ❌ | ✅ | - | - |
| `WY18B` | - | - | - | ✅ | ❌ |
| `WY19B` | - | - | - | ✅ | ❌ |
| `WY20P` | - | - | - | ✅ | ❌ |
| `WY0S` | - | - | - | ✅ | ❌ |
| `WY1S` | - | - | - | ✅ | ❌ |
| `WY18P` | - | - | - | ❌ | ✅ |
| `WY19P` | - | - | - | ❌ | ✅ |
| Wheel Code | Legacy M3 | Highland M3 | Highland M3P | Legacy MY | Juniper MY | Juniper MY Perf |
|------------|-----------|-------------|--------------|-----------|------------|-----------------|
| `W38B` | ✅ | ❌ | ❌ | - | - | - |
| `W39B` | ✅ | ❌ | ❌ | - | - | - |
| `W32P` | ✅ | ❌ | ❌ | - | - | - |
| `W38A` | ❌ | ✅ | ❌ | - | - | - |
| `W30P` | ❌ | ❌ | ✅ | - | - | - |
| `WY18B` | - | - | - | ✅ | ❌ | ❌ |
| `WY19B` | - | - | - | ✅ | ❌ | ❌ |
| `WY20P` | - | - | - | ✅ | ❌ | ❌ |
| `WY0S` | - | - | - | ✅ | ❌ | ❌ |
| `WY1S` | - | - | - | ✅ | ❌ | ❌ |
| `WY18P` | - | - | - | ❌ | ✅ | ❌ |
| `WY19P` | - | - | - | ❌ | ✅ | ❌ |
| `WY20A` | - | - | - | ❌ | ✅ | ❌ |
| `WY21A` | - | - | - | ❌ | ❌ | ✅ |
---
@@ -227,6 +249,7 @@ Format: `{model_variant}_{color_code}_{wheel_code}.png`
| Highland M3 Performance | `m3hp_PR01_W30P.png` |
| Legacy Model Y | `my_PPSW_WY19B.png` |
| Juniper Model Y | `myj_PX02_WY18P.png` |
| Juniper MY Performance | `myjp_PN01_WY21A.png` |
| Model S | `ms_PPSW_WT19.png` |
| Model X | `mx_PPSB_WX20.png` |
@@ -240,10 +263,11 @@ Format: `{model_variant}_{color_code}_{wheel_code}.png`
| Highland Model 3 | 7 | 1 | 7 | PNG |
| Highland M3 Performance | 7 | 1 | 7 | PNG |
| Legacy Model Y | 5 | 5 | 25 | PNG |
| Juniper Model Y | 3 | 2 | 6 | PNG |
| Juniper Model Y | 6 | 3 | 15 | PNG |
| Juniper MY Performance | 6 | 1 | 6 | PNG |
| Model S | 5 | 1 | 5 | PNG |
| Model X | 5 | 1 | 5 | PNG |
| **Total** | | | **76** | **~7 MB** |
| **Total** | | | **91** | **~9 MB** |
---
+31 -3
View File
@@ -91,7 +91,8 @@ LEGACY_MY = {
}
# Juniper Model Y (2025+)
# MTY68 = Standard Juniper configuration
# MTY68 = Standard/Long Range configuration (18"/19" wheels)
# MTY60 = Premium configuration with 20" Helix wheels
JUNIPER_MY = {
"model_code": "my",
"file_prefix": "myj", # j = juniper
@@ -99,7 +100,33 @@ JUNIPER_MY = {
"trim_code": "MTY68",
"interior_code": "IBB3",
"colors": ["PPSW", "PN01", "PX02"],
"wheels": ["WY18P", "WY19P"], # WY18P = Photon 18", WY19P = Crossflow 19"
"wheels": ["WY18P", "WY19P"], # WY18P = Photon 18" (Standard), WY19P = Crossflow 19" (Premium)
"compositor": "new",
}
# Juniper Model Y Premium (2025+)
# MTY60 supports more colors than MTY68 for 19"/20" wheels
JUNIPER_MY_PREMIUM = {
"model_code": "my",
"file_prefix": "myj", # Same prefix, different wheel
"name": "Model Y Juniper Premium",
"trim_code": "MTY60",
"interior_code": "IPB8",
"colors": ["PPSW", "PN01", "PX02", "PN00", "PR01", "PPSB"], # 6 colors
"wheels": ["WY19P", "WY20A"], # 19" Crossflow and 20" Helix 2.0
"compositor": "new",
}
# Juniper Model Y Performance (2025+)
# MTY53 = Performance configuration with red calipers
JUNIPER_MY_PERF = {
"model_code": "my",
"file_prefix": "myjp", # jp = juniper performance
"name": "Model Y Juniper Performance",
"trim_code": "MTY53",
"interior_code": "IPB10",
"colors": ["PPSW", "PN01", "PX02", "PB02", "PN00", "PR01"], # All 6 colors available
"wheels": ["WY21A"], # 21" Überturbine wheels
"compositor": "new",
}
@@ -124,7 +151,7 @@ MODEL_X = {
}
# All model configurations
ALL_MODELS = [LEGACY_M3, HIGHLAND_M3, HIGHLAND_M3_PERF, LEGACY_MY, JUNIPER_MY, MODEL_S, MODEL_X]
ALL_MODELS = [LEGACY_M3, HIGHLAND_M3, HIGHLAND_M3_PERF, LEGACY_MY, JUNIPER_MY, JUNIPER_MY_PREMIUM, JUNIPER_MY_PERF, MODEL_S, MODEL_X]
# Color name mapping for display
COLOR_NAMES = {
@@ -140,6 +167,7 @@ COLOR_NAMES = {
"PR00": "Midnight Cherry Red",
"PR01": "Ultra Red",
"PX02": "Black Diamond",
"PB02": "Deep Blue", # Juniper-only Deep Blue (different from PPSB)
}