Skip to content

Commit 3645766

Browse files
authored
Feat/seat climate (#27)
* init config and types for Car Seat Climate Options * add climate seat configs to various bluelink sub classes * support seat selection in custom climate configurations * tweaks before merge to ensure old config for custom climates is supported
1 parent 31c3f3f commit 3645766

File tree

9 files changed

+201
-19
lines changed

9 files changed

+201
-19
lines changed

src/app.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { Config, getConfig, STANDARD_CLIMATE_OPTIONS } from 'config'
22
import { Bluelink, Status, ClimateRequest, ChargeLimit } from './lib/bluelink-regions/base'
33
import { getTable, Div, P, Img, quickOptions, DivChild, Spacer, destructiveConfirm } from 'lib/scriptable-utils'
4-
import { loadConfigScreen, deleteConfig, setConfig } from 'config'
4+
import {
5+
loadConfigScreen,
6+
deleteConfig,
7+
setConfig,
8+
ClimateSeatSetting,
9+
ClimateSeatSettingCool,
10+
ClimateSeatSettingWarm,
11+
} from 'config'
512
import { Version } from 'lib/version'
613
import { loadAboutScreen, doDowngrade } from 'about'
714
import { deleteWidgetCache } from 'widget'
@@ -393,14 +400,48 @@ const pageIcons = connect(
393400
command: 'climate',
394401
bl: bl,
395402
payload: payload
396-
? ({ ...payload, enable: true } as ClimateRequest)
403+
? ({
404+
...payload,
405+
enable: true,
406+
...(payload.seatClimate &&
407+
payload.seatClimate !== 'Off' && {
408+
seatClimate: {
409+
driver: ClimateSeatSetting[payload.seatClimate],
410+
passenger: ['ALL', 'FRONT'].includes(payload.seatClimateSettings)
411+
? ClimateSeatSetting[payload.seatClimate]
412+
: 0,
413+
rearLeft: ['ALL'].includes(payload.seatClimateSettings)
414+
? ClimateSeatSetting[payload.seatClimate]
415+
: 0,
416+
rearRight: ['ALL'].includes(payload.seatClimateSettings)
417+
? ClimateSeatSetting[payload.seatClimate]
418+
: 0,
419+
},
420+
}),
421+
} as ClimateRequest)
397422
: ({
398423
enable: opt !== 'Off' ? true : false,
399424
frontDefrost: opt === 'Warm' ? true : false,
400425
rearDefrost: opt === 'Warm' ? true : false,
401426
steering: opt === 'Warm' ? true : false,
402427
temp: opt === 'Warm' ? config.climateTempWarm : config.climateTempCold,
403428
durationMinutes: 15,
429+
...(config.climateSeatLevel !== 'Off' && {
430+
seatClimate:
431+
opt === 'Warm'
432+
? {
433+
driver: ClimateSeatSettingWarm[config.climateSeatLevel],
434+
passenger: ClimateSeatSettingWarm[config.climateSeatLevel],
435+
rearLeft: ClimateSeatSettingWarm[config.climateSeatLevel],
436+
rearRight: ClimateSeatSettingWarm[config.climateSeatLevel],
437+
}
438+
: {
439+
driver: ClimateSeatSettingCool[config.climateSeatLevel],
440+
passenger: ClimateSeatSettingCool[config.climateSeatLevel],
441+
rearLeft: ClimateSeatSettingCool[config.climateSeatLevel],
442+
rearRight: ClimateSeatSettingCool[config.climateSeatLevel],
443+
},
444+
}),
404445
} as ClimateRequest),
405446
actions: updatingActions,
406447
actionKey: 'climate',

src/config.ts

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,30 @@ export interface Auth {
1212
region: string
1313
}
1414

15+
export const ClimateSeatSettingCool: Record<string, number> = {
16+
Off: 0,
17+
Low: 3,
18+
Medium: 4,
19+
High: 5,
20+
}
21+
22+
export const ClimateSeatSettingWarm: Record<string, number> = {
23+
Off: 0,
24+
Low: 6,
25+
Medium: 7,
26+
High: 8,
27+
}
28+
29+
export const ClimateSeatSetting: Record<string, number> = {
30+
Off: 0,
31+
'Cool - Low': 3,
32+
'Cool - Medium': 4,
33+
'Cool - High': 5,
34+
'Heat - Low': 6,
35+
'Heat - Medium': 7,
36+
'Heat - High': 8,
37+
}
38+
1539
export interface CustomClimateConfig {
1640
name: string
1741
tempType: 'C' | 'F'
@@ -20,6 +44,8 @@ export interface CustomClimateConfig {
2044
rearDefrost: boolean
2145
steering: boolean
2246
durationMinutes: number
47+
seatClimate: string
48+
seatClimateSettings: 'DRIVER' | 'FRONT' | 'ALL'
2349
}
2450

2551
export interface ChargeLimitConfig {
@@ -35,6 +61,7 @@ export interface Config {
3561
distanceUnit: 'km' | 'mi'
3662
climateTempWarm: number
3763
climateTempCold: number
64+
climateSeatLevel: string
3865
allowWidgetRemoteRefresh: boolean
3966
carColor: string
4067
debugLogging: boolean
@@ -66,6 +93,7 @@ export interface FlattenedConfig {
6693
distanceUnit: 'km' | 'mi'
6794
climateTempWarm: number
6895
climateTempCold: number
96+
climateSeatLevel: string
6997
allowWidgetRemoteRefresh: boolean
7098
carColor: string
7199
debugLogging: boolean
@@ -105,6 +133,7 @@ const DEFAULT_CONFIG = {
105133
distanceUnit: 'km',
106134
climateTempCold: DEFAULT_TEMPS.C.cold,
107135
climateTempWarm: DEFAULT_TEMPS.C.warm,
136+
climateSeatLevel: 'Off',
108137
debugLogging: false,
109138
multiCar: false,
110139
promptForUpdate: true,
@@ -205,6 +234,7 @@ export async function loadConfigScreen(bl: Bluelink | undefined = undefined) {
205234
distanceUnit,
206235
climateTempWarm,
207236
climateTempCold,
237+
climateSeatLevel,
208238
debugLogging,
209239
multiCar,
210240
promptForUpdate,
@@ -229,6 +259,7 @@ export async function loadConfigScreen(bl: Bluelink | undefined = undefined) {
229259
distanceUnit: distanceUnit,
230260
climateTempCold: climateTempCold,
231261
climateTempWarm: climateTempWarm,
262+
climateSeatLevel: climateSeatLevel,
232263
allowWidgetRemoteRefresh: allowWidgetRemoteRefresh,
233264
carColor: carColor ? carColor.toLocaleLowerCase() : 'white',
234265
debugLogging: debugLogging,
@@ -335,6 +366,12 @@ export async function loadConfigScreen(bl: Bluelink | undefined = undefined) {
335366
label: 'Climate temp when pre-cooling (whole number or .5)',
336367
isRequired: true,
337368
},
369+
climateSeatLevel: {
370+
type: 'dropdown',
371+
label: 'Climate Seat Setting',
372+
isRequired: true,
373+
options: Object.keys(ClimateSeatSettingCool),
374+
},
338375
carColor: {
339376
type: 'dropdown',
340377
label: 'Car Color (Will default to white if not available)',
@@ -499,22 +536,34 @@ export async function loadWidgetConfigScreen() {
499536

500537
export async function loadCustomClimateConfig(climateConfig: CustomClimateConfig | undefined) {
501538
const previousName = climateConfig ? climateConfig.name : undefined
502-
if (!climateConfig) {
503-
climateConfig = {
504-
name: '',
505-
tempType: 'C',
506-
temp: DEFAULT_TEMPS.C.warm,
507-
frontDefrost: true,
508-
rearDefrost: true,
509-
steering: true,
510-
durationMinutes: 15,
511-
} as CustomClimateConfig
512-
}
539+
const defaultClimateConfig = {
540+
name: '',
541+
tempType: 'C',
542+
temp: DEFAULT_TEMPS.C.warm,
543+
frontDefrost: true,
544+
rearDefrost: true,
545+
steering: true,
546+
durationMinutes: 15,
547+
seatClimate: 'OFF',
548+
seatClimateSettings: 'ALL',
549+
} as CustomClimateConfig
550+
if (!climateConfig) climateConfig = defaultClimateConfig
551+
else climateConfig = { ...defaultClimateConfig, ...climateConfig } // merge with default config
513552

514553
return await form<CustomClimateConfig & { delete: boolean }>({
515554
title: 'Custom Climate Configuration',
516555
subtitle: previousName ? `Editing configuration: ${previousName}` : 'Create new configuration',
517-
onSubmit: ({ name, tempType, temp, frontDefrost, rearDefrost, steering, durationMinutes }) => {
556+
onSubmit: ({
557+
name,
558+
tempType,
559+
temp,
560+
frontDefrost,
561+
rearDefrost,
562+
steering,
563+
durationMinutes,
564+
seatClimate,
565+
seatClimateSettings,
566+
}) => {
518567
const config = getConfig()
519568
const newConfig = {
520569
name: name,
@@ -524,6 +573,8 @@ export async function loadCustomClimateConfig(climateConfig: CustomClimateConfig
524573
rearDefrost: rearDefrost,
525574
steering: steering,
526575
durationMinutes: durationMinutes,
576+
seatClimate: seatClimate || 'OFF',
577+
seatClimateSettings: seatClimateSettings || 'ALL',
527578
} as CustomClimateConfig
528579
if (previousName) {
529580
const index = config.customClimates.findIndex((x) => x.name === previousName)
@@ -599,6 +650,18 @@ export async function loadCustomClimateConfig(climateConfig: CustomClimateConfig
599650
label: 'Number of Minutes to run climate',
600651
isRequired: true,
601652
},
653+
seatClimate: {
654+
type: 'dropdown',
655+
label: 'Seat Climate Setting',
656+
isRequired: true,
657+
options: Object.keys(ClimateSeatSetting),
658+
},
659+
seatClimateSettings: {
660+
type: 'dropdown',
661+
label: 'Seat Climate Settings',
662+
isRequired: true,
663+
options: ['DRIVER', 'FRONT', 'ALL'],
664+
},
602665
delete: {
603666
type: 'clickable',
604667
label: 'Delete Climate Configuration',

src/lib/bluelink-regions/base.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,21 @@ export interface TempConversion {
9090
H: string[]
9191
}
9292

93+
export interface SeatClimate {
94+
driver: number
95+
passenger: number
96+
rearLeft: number
97+
rearRight: number
98+
}
99+
93100
export interface ClimateRequest {
94101
enable: boolean
95102
frontDefrost: boolean
96103
rearDefrost: boolean
97104
steering: boolean
98105
temp: number
99106
durationMinutes: number
107+
seatClimate?: SeatClimate
100108
}
101109

102110
export interface ChargeLimit {

src/lib/bluelink-regions/canada.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,14 @@ export class BluelinkCanada extends Bluelink {
485485
},
486486
igniOnDuration: config.durationMinutes,
487487
heating1: this.getHeatingValue(config.rearDefrost, config.steering),
488+
...(config.seatClimate && {
489+
seatHeaterVentCMD: {
490+
drvSeatOptCmd: config.seatClimate.driver,
491+
astSeatOptCmd: config.seatClimate.passenger,
492+
rlSeatOptCmd: config.seatClimate.rearLeft,
493+
rrSeatOptCmd: config.seatClimate.rearRight,
494+
},
495+
}),
488496
},
489497
}),
490498
headers: {

src/lib/bluelink-regions/europe.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,14 @@ export class BluelinkEurope extends Bluelink {
690690
tempUnit: this.config.tempType,
691691
drvSeatLoc: this.distanceUnit === 'mi' ? 'R' : 'L',
692692
hvacTemp: config.temp,
693+
...(config.seatClimate && {
694+
seatClimateInfo: {
695+
drvSeatClimateState: config.seatClimate.driver,
696+
psgSeatClimateState: config.seatClimate.passenger,
697+
rlSeatClimateState: config.seatClimate.rearLeft,
698+
rrSeatClimateState: config.seatClimate.rearRight,
699+
},
700+
}),
693701
})
694702
}
695703

src/lib/bluelink-regions/usa-kia.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,14 @@ export class BluelinkUSAKia extends Bluelink {
445445
rearWindow: Number(config.rearDefrost),
446446
sideMirror: Number(config.rearDefrost),
447447
},
448+
...(config.seatClimate && {
449+
heatVentSeat: {
450+
driverSeat: config.seatClimate.driver,
451+
passengerSeat: config.seatClimate.passenger,
452+
rearLeftSeat: config.seatClimate.rearLeft,
453+
rearRightSeat: config.seatClimate.rearRight,
454+
},
455+
}),
448456
},
449457
}),
450458
headers: {

src/lib/bluelink-regions/usa.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,14 @@ export class BluelinkUSA extends Bluelink {
397397
},
398398
// igniOnDuration: config.durationMinutes, // not supported in US
399399
heating1: this.getHeatingValue(config.rearDefrost, config.steering),
400+
...(config.seatClimate && {
401+
seatHeaterVentInfo: {
402+
drvSeatHeatState: config.seatClimate.driver,
403+
astSeatHeatState: config.seatClimate.passenger,
404+
rlSeatHeatState: config.seatClimate.rearLeft,
405+
rrSeatHeatState: config.seatClimate.rearRight,
406+
},
407+
}),
400408
}),
401409
notJSON: true,
402410
headers: {

0 commit comments

Comments
 (0)