Skip to content

Commit 7e730be

Browse files
committed
WIP #2 for usa support
1 parent b608372 commit 7e730be

File tree

6 files changed

+48
-31
lines changed

6 files changed

+48
-31
lines changed

src/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ async function doAsyncUpdate(props: doAsyncUpdateProps) {
458458

459459
// log error on failure
460460
if (!didSucceed) {
461-
logError(data)
461+
logError(JSON.stringify(data))
462462
}
463463
} else {
464464
// continue to rotate icon indicating ongoing update

src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export interface FlattenedConfig {
3434
vin: string | undefined
3535
}
3636

37-
const SUPPORTED_REGIONS = ['canada']
37+
const SUPPORTED_REGIONS = ['canada', 'usa']
3838
const SUPPORTED_MANUFACTURERS = ['Hyundai', 'Kia']
3939

4040
const DEFAULT_TEMPS = {

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { confirm } from './lib/scriptable-utils'
3535
App.close() // add this back after dev
3636
return resp
3737
} catch (error) {
38-
logError(error)
38+
logError(JSON.stringify(error))
3939
}
4040
}
4141
})()

src/lib/bluelink-regions/base.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export class Bluelink {
102102
protected loginFailure: boolean
103103

104104
constructor(config: Config, vin?: string) {
105+
this.config = config
105106
this.vin = vin
106107
this.apiDomain = DEFAULT_API_DOMAIN
107108
this.statusCheckInterval = DEFAULT_STATUS_CHECK_INTERVAL
@@ -115,7 +116,6 @@ export class Bluelink {
115116
}
116117

117118
protected async superInit(config: Config, statusCheckInterval?: number) {
118-
this.config = config
119119
this.vin = this.config.vin
120120
this.statusCheckInterval = statusCheckInterval || DEFAULT_STATUS_CHECK_INTERVAL
121121

@@ -315,11 +315,14 @@ export class Bluelink {
315315
}),
316316
}
317317
try {
318+
if (this.config.debugLogging) await this.logger.log(`Sending request ${JSON.stringify(this.debugLastRequest)}`)
318319
const json = await req.loadJSON()
320+
await this.logger.log(`response ${JSON.stringify(req.response)} data: ${JSON.stringify(json)}`)
319321
return { resp: req.response, json: json }
320322
} catch (error) {
321-
await this.logger.log(`Failed to send request to ${props.url}, error ${error}`)
322-
throw Error(`Failed to send request to ${props.url}, error ${error}`)
323+
const errorString = `Failed to send request to ${props.url}, request ${JSON.stringify(this.debugLastRequest)} - error ${error}`
324+
if (this.config.debugLogging) await this.logger.log(error)
325+
throw Error(errorString)
323326
}
324327
}
325328

src/lib/bluelink-regions/usa.ts

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,38 @@ import {
88
} from './base'
99
import { Config } from '../../config'
1010

11-
const DEFAULT_API_DOMAIN = 'https://api.telematics.hyundaiusa.com/ac/v2/'
11+
const DEFAULT_API_DOMAIN = 'https://api.telematics.hyundaiusa.com/'
1212
const API_DOMAINS: Record<string, string> = {
13-
hyundai: 'https://api.telematics.hyundaiusa.com/ac/v2/',
13+
hyundai: 'https://api.telematics.hyundaiusa.com/',
14+
kia: 'https://api.owners.kia.com/apigw/v1/',
1415
}
1516

1617
export class BluelinkUSA extends Bluelink {
18+
private carVin: string | undefined
19+
private carId: string | undefined
20+
1721
constructor(config: Config, statusCheckInterval?: number) {
1822
super(config)
1923
this.apiDomain = config.manufacturer
2024
? this.getApiDomain(config.manufacturer, API_DOMAINS, DEFAULT_API_DOMAIN)
2125
: DEFAULT_API_DOMAIN
26+
2227
this.statusCheckInterval = statusCheckInterval || DEFAULT_STATUS_CHECK_INTERVAL
2328
this.additionalHeaders = {
2429
from: 'SPA',
30+
to: 'ISS',
2531
language: '0',
2632
offset: `-${new Date().getTimezoneOffset() / 60}`,
2733
gen: '2',
28-
client_id: 'm66129Bb-em93-SPAHYN-bZ91-am4540zp19920',
29-
clientSecret: 'v558o935-6nne-423i-baa8',
34+
client_id:
35+
config.manufacturer && config.manufacturer === 'kia' ? 'MWAMOBILE' : 'm66129Bb-em93-SPAHYN-bZ91-am4540zp19920',
36+
clientSecret:
37+
config.manufacturer && config.manufacturer === 'kia' ? '98er-w34rf-ibf3-3f6h' : 'v558o935-6nne-423i-baa8',
3038
username: this.config.auth.username,
31-
blueLinkServicePin: this.config.auth.pin,
39+
blueLinkServicePin: `${this.config.auth.pin}`,
40+
brandIndicator: 'H',
3241
}
42+
3343
this.authHeader = 'accessToken'
3444
this.tempLookup = {
3545
F: [62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82],
@@ -67,22 +77,23 @@ export class BluelinkUSA extends Bluelink {
6777
}
6878

6979
private requestResponseValid(resp: Record<string, any>): boolean {
70-
if (Object.hasOwn(resp, 'statusCode') && resp['statusCode'] == '200') {
80+
if (Object.hasOwn(resp, 'statusCode') && resp.statusCode === 200) {
7181
return true
7282
}
7383
return false
7484
}
7585

7686
private carHeaders(): Record<string, string> {
7787
return {
78-
registrationId: this.cache.car.id,
79-
vin: this.cache.car.vin,
88+
// on first load cache is not populated - hence default to optional local vars set when fetching the car.
89+
registrationId: this.cache ? this.cache.car.id : this.carId!,
90+
vin: this.cache ? this.cache.car.vin : this.carVin!,
8091
}
8192
}
8293

8394
protected async login(): Promise<BluelinkTokens | undefined> {
8495
const resp = await this.request({
85-
url: this.apiDomain.replace('/ac/v2/', '/v2/ac/oauth/token'),
96+
url: this.apiDomain + 'v2/ac/oauth/token',
8697
data: JSON.stringify({
8798
username: this.config.auth.username,
8899
password: this.config.auth.password,
@@ -93,7 +104,7 @@ export class BluelinkUSA extends Bluelink {
93104
return {
94105
accessToken: resp.json.access_token,
95106
refreshToken: resp.json.refresh_token,
96-
expiry: Math.floor(Date.now() / 1000) + resp.json.result.token.expires_in, // we only get a expireIn not a actual date
107+
expiry: Math.floor(Date.now() / 1000) + resp.json.expires_in, // we only get a expireIn not a actual date
97108
}
98109
}
99110

@@ -104,7 +115,7 @@ export class BluelinkUSA extends Bluelink {
104115

105116
protected async refreshTokens(): Promise<BluelinkTokens | undefined> {
106117
const resp = await this.request({
107-
url: this.apiDomain.replace('/ac/v2/', '/v2/ac/oauth/token/refresh'),
118+
url: this.apiDomain + 'v2/ac/oauth/token/refresh',
108119
data: JSON.stringify({
109120
refresh_token: this.cache.token.refreshToken,
110121
}),
@@ -114,7 +125,7 @@ export class BluelinkUSA extends Bluelink {
114125
return {
115126
accessToken: resp.json.access_token,
116127
refreshToken: resp.json.refresh_token,
117-
expiry: Math.floor(Date.now() / 1000) + resp.json.result.token.expires_in, // we only get a expireIn not a actual date
128+
expiry: Math.floor(Date.now() / 1000) + resp.json.expires_in, // we only get a expireIn not a actual date
118129
}
119130
}
120131

@@ -125,20 +136,22 @@ export class BluelinkUSA extends Bluelink {
125136

126137
protected async getCar(): Promise<BluelinkCar> {
127138
const resp = await this.request({
128-
url: this.apiDomain + `enrollment/details/${this.config.auth.username}`,
129-
method: 'POST',
139+
url: this.apiDomain + `ac/v2/enrollment/details/${this.config.auth.username}`,
130140
})
131141
if (this.requestResponseValid(resp.resp) && resp.json.enrolledVehicleDetails.length > 0) {
132-
let vehicle = resp.json.result.enrolledVehicleDetails[0]
142+
let vehicle = resp.json.enrolledVehicleDetails[0].vehicleDetails
133143
if (this.vin) {
134-
for (const v of resp.json.result.enrolledVehicleDetails) {
135-
if (v.vin === this.vin) {
136-
vehicle = v
144+
for (const v of resp.json.enrolledVehicleDetails) {
145+
if (v.vehicleDetails.vin === this.vin) {
146+
vehicle = v.vehicleDetails
137147
break
138148
}
139149
}
140150
}
141151

152+
await this.logger.log(`Choose car ${JSON.stringify(vehicle)}`)
153+
this.carVin = vehicle.vin
154+
this.carId = vehicle.regid
142155
return {
143156
id: vehicle.regid,
144157
vin: vehicle.vin,
@@ -165,9 +178,9 @@ export class BluelinkUSA extends Bluelink {
165178
isCharging: status.evStatus.batteryCharge,
166179
isPluggedIn: status.evStatus.batteryPlugin > 0 ? true : false,
167180
chargingPower: status.evStatus.batteryCharge // only check for charging power if actually charging
168-
? (status.evStatus.batteryPower.batteryFstChrgPower && status.evStatus.batteryPower.batteryFstChrgPower) > 0
169-
? status.evStatus.batteryPower.batteryFstChrgPower
170-
: status.evStatus.batteryPower.batteryStndChrgPower
181+
? (status.evStatus.batteryFstChrgPower && status.evStatus.batteryFstChrgPower) > 0
182+
? status.evStatus.batteryFstChrgPower
183+
: status.evStatus.batteryStndChrgPower
171184
: 0,
172185
remainingChargeTimeMins: status.evStatus.remainTime2.atc.value,
173186
// sometimes range back as zero? if so ignore and use cache
@@ -186,14 +199,12 @@ export class BluelinkUSA extends Bluelink {
186199
}
187200

188201
protected async getCarStatus(id: string, forceUpdate: boolean): Promise<BluelinkStatus> {
189-
const api = 'rcs/rvs/vehicleStatus'
202+
const api = 'ac/v2/rcs/rvs/vehicleStatus'
190203
const resp = await this.request({
191204
url: this.apiDomain + api,
192205
headers: {
193206
...this.carHeaders(),
194-
...(forceUpdate && {
195-
REFRESH: 'true',
196-
}),
207+
refresh: forceUpdate ? 'true' : 'false',
197208
},
198209
})
199210

src/lib/bluelink.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { Bluelink } from './bluelink-regions/base'
22
import { Config } from 'config'
33
import { BluelinkCanada } from './bluelink-regions/canada'
4+
import { BluelinkUSA } from './bluelink-regions/usa'
45

56
export async function initRegionalBluelink(config: Config): Promise<BluelinkCanada | Bluelink | undefined> {
67
switch (config.auth.region) {
78
case 'canada':
89
return await BluelinkCanada.init(config)
10+
case 'usa':
11+
return await BluelinkUSA.init(config)
912
default:
1013
return
1114
}

0 commit comments

Comments
 (0)