Skip to content

Commit 47fb431

Browse files
authored
Europe Hyundai / Kia Support (#4)
* WIP: Europe support * auth working! * Europe support continued: refreshTokens, getDeviceId, getCar added * working app skeleton / status working * fix remote status being different JSON than cached * app colors for light / dark mode * Europe - working for UK enabled other countries * adjust logic for determining charge and power - making them seperate. Deal with lack of power in app and widget * adjust logic for determining charge and power #2 * remove language / sub-region and move to preferred distance unit. Europe deal with login failure and URI encode username/password * Europe switch to CCS2 status commands + handle CCS2 header correctly. * fix ccuCCS2ProtocolSupport setting * finalize europe charging power attribute + made width of charging rate based on number size * add kia europe settings * chore: prettier fix * ioniq 5N image
1 parent 0471df8 commit 47fb431

File tree

14 files changed

+946
-79
lines changed

14 files changed

+946
-79
lines changed
60.1 KB
Loading

package-lock.json

Lines changed: 63 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"globals": "^15.14.0",
2626
"prettier": "^3.4.2",
2727
"rollup": "^4.30.1",
28+
"rollup-plugin-polyfill-node": "^0.13.0",
2829
"tslib": "^2.8.1",
2930
"typescript": "^5.7.3"
3031
}

rollup.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import typescript from '@rollup/plugin-typescript'
22
import { nodeResolve } from '@rollup/plugin-node-resolve'
3+
import nodePolyfills from 'rollup-plugin-polyfill-node'
34
import terser from '@rollup/plugin-terser'
45

56
import addFileIconSettings from './rollup-plugin-add-file-icon-settings'
@@ -23,7 +24,7 @@ const config = {
2324
addFileIconSettings(),
2425
],
2526
},
26-
plugins: [typescript(), nodeResolve()],
27+
plugins: [typescript(), nodeResolve(), nodePolyfills(/* options */)],
2728
watch: {
2829
include: 'src/**',
2930
},

src/app.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ interface updatingActions {
3535

3636
let isUpdating = false
3737
let updatingIconAngle = 0
38+
const darkMode = Device.isUsingDarkAppearance()
3839

3940
const { present, connect, setState } = getTable<{
4041
name: string
@@ -58,7 +59,7 @@ const { present, connect, setState } = getTable<{
5859
const MIN_API_REFRESH_TIME = 900000 // 15 minutes
5960

6061
export async function createApp(config: Config, bl: Bluelink) {
61-
await loadTintedIcons()
62+
await loadTintedIcons(darkMode)
6263

6364
// not blocking call - render UI with last cache and then update from a non forced remote call (i.e. to server but not to car)
6465
// if its been at least MIN_API_REFRESH_TIME milliseconds
@@ -187,12 +188,24 @@ const pageIcons = connect(
187188
const lastSeen = new Date(lastUpdated)
188189
const batteryIcon = isCharging ? 'charging' : 'not-charging'
189190
const batteryText = 'Not Charging'
191+
const chargingPowerText = chargingPower > 0 ? `${chargingPower.toFixed(1).toString()} kW` : '- kW'
192+
let chargingPowerTextRowPercentage = '25%'
193+
194+
// annoying but impacts UI fairly significantly.
195+
if (chargingPowerText.length <= 4)
196+
chargingPowerTextRowPercentage = '15%' // '? kw'
197+
else if (chargingPowerText.length <= 6)
198+
chargingPowerTextRowPercentage = '18%' // '1.2 kw'
199+
else if (chargingPowerText.length <= 7)
200+
chargingPowerTextRowPercentage = '21%' // '10.5 kw'
201+
else if (chargingPowerText.length <= 8) chargingPowerTextRowPercentage = '25%' // '222.1 kw'
190202

191203
const chargingRow: DivChild[] = []
192204
if (updatingActions && updatingActions.charge) {
193-
chargingRow.push(P(updatingActions.charge.text, { align: 'left', width: '70%', color: Color.yellow() }))
205+
chargingRow.push(P(updatingActions.charge.text, { align: 'left', width: '70%', color: Color.orange() }))
194206
} else if (isCharging) {
195-
chargingRow.push(P(`${chargingPower.toString()} kW`, { align: 'left', width: '20%' }))
207+
// @ts-ignore
208+
chargingRow.push(P(chargingPowerText, { align: 'left', width: chargingPowerTextRowPercentage }))
196209
chargingRow.push(Img(getTintedIcon('charging-complete'), { align: 'left', width: '10%' }))
197210
chargingRow.push(P(`${getChargeCompletionString(lastSeen, remainingChargeTimeMins)}`, { align: 'left' }))
198211
} else {
@@ -261,7 +274,7 @@ const pageIcons = connect(
261274
P(updatingActions && updatingActions.climate ? updatingActions.climate.text : conditioningText, {
262275
align: 'left',
263276
width: '70%',
264-
...(updatingActions && updatingActions.climate && { color: Color.yellow() }),
277+
...(updatingActions && updatingActions.climate && { color: Color.orange() }),
265278
}),
266279
],
267280
{
@@ -332,7 +345,7 @@ const pageIcons = connect(
332345
P(updatingActions && updatingActions.lock ? updatingActions.lock.text : lockedText, {
333346
align: 'left',
334347
width: '70%',
335-
...(updatingActions && updatingActions.lock && { color: Color.yellow() }),
348+
...(updatingActions && updatingActions.lock && { color: Color.orange() }),
336349
}),
337350
],
338351
{
@@ -379,7 +392,7 @@ const pageIcons = connect(
379392
{
380393
align: 'left',
381394
width: '70%',
382-
...(updatingActions && updatingActions.status && { color: Color.yellow() }),
395+
...(updatingActions && updatingActions.status && { color: Color.orange() }),
383396
},
384397
),
385398
],
@@ -453,7 +466,11 @@ async function doAsyncUpdate(props: doAsyncUpdateProps) {
453466
updatingActions: {
454467
[props.actionKey]: {
455468
image: didSucceed
456-
? await getAngledTintedIconAsync('checkmark.arrow.trianglehead.counterclockwise', Color.green(), 0)
469+
? await getAngledTintedIconAsync(
470+
'checkmark.arrow.trianglehead.counterclockwise',
471+
darkMode ? Color.green() : Color.green(),
472+
0,
473+
)
457474
: await getAngledTintedIconAsync(
458475
'exclamationmark.arrow.trianglehead.2.clockwise.rotate.90',
459476
Color.red(),
@@ -491,7 +508,7 @@ async function doAsyncUpdate(props: doAsyncUpdateProps) {
491508
setState({
492509
updatingActions: {
493510
[props.actionKey]: {
494-
image: await getAngledTintedIconAsync('arrow.trianglehead.clockwise', Color.yellow(), updatingIconAngle),
511+
image: await getAngledTintedIconAsync('arrow.trianglehead.clockwise', Color.orange(), updatingIconAngle),
495512
text: props.updatingText,
496513
},
497514
},

src/config.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ export interface Auth {
1212
}
1313

1414
export interface Config {
15-
manufacturer: string | undefined
15+
manufacturer: string
1616
auth: Auth
1717
tempType: 'C' | 'F'
18+
distanceUnit: 'km' | 'mi'
1819
climateTempWarm: number
1920
climateTempCold: number
2021
allowWidgetRemoteRefresh: boolean
@@ -44,12 +45,13 @@ export interface CustomClimateConfig {
4445
}
4546

4647
export interface FlattenedConfig {
47-
manufacturer: string | undefined
48+
manufacturer: string
4849
username: string
4950
password: string
5051
pin: string
5152
region: string
5253
tempType: 'C' | 'F'
54+
distanceUnit: 'km' | 'mi'
5355
climateTempWarm: number
5456
climateTempCold: number
5557
allowWidgetRemoteRefresh: boolean
@@ -60,9 +62,8 @@ export interface FlattenedConfig {
6062
}
6163

6264
// const SUPPORTED_REGIONS = ['canada']
63-
const SUPPORTED_REGIONS = ['canada', 'usa']
65+
const SUPPORTED_REGIONS = ['canada', 'usa', 'europe']
6466
const SUPPORTED_MANUFACTURERS = ['Hyundai', 'Kia']
65-
6667
const DEFAULT_TEMPS = {
6768
C: {
6869
cold: 19,
@@ -83,11 +84,12 @@ const DEFAULT_CONFIG = {
8384
region: '',
8485
},
8586
tempType: 'C',
87+
distanceUnit: 'km',
8688
climateTempCold: DEFAULT_TEMPS.C.cold,
8789
climateTempWarm: DEFAULT_TEMPS.C.warm,
8890
debugLogging: false,
8991
allowWidgetRemoteRefresh: false,
90-
manufacturer: undefined,
92+
manufacturer: 'hyundai',
9193
customClimates: [],
9294
widgetConfig: {
9395
standardPollPeriod: 1,
@@ -149,6 +151,7 @@ export async function loadConfigScreen() {
149151
region,
150152
pin,
151153
tempType,
154+
distanceUnit,
152155
climateTempWarm,
153156
climateTempCold,
154157
debugLogging,
@@ -168,6 +171,7 @@ export async function loadConfigScreen() {
168171
pin: pin,
169172
},
170173
tempType: tempType,
174+
distanceUnit: distanceUnit,
171175
climateTempCold: climateTempCold,
172176
climateTempWarm: climateTempWarm,
173177
allowWidgetRemoteRefresh: allowWidgetRemoteRefresh,
@@ -237,7 +241,7 @@ export async function loadConfigScreen() {
237241
label: 'Choose your Car Manufacturer',
238242
options: SUPPORTED_MANUFACTURERS,
239243
allowCustom: false,
240-
isRequired: false,
244+
isRequired: true,
241245
},
242246
vin: {
243247
type: 'textInput',
@@ -251,6 +255,13 @@ export async function loadConfigScreen() {
251255
allowCustom: false,
252256
isRequired: true,
253257
},
258+
distanceUnit: {
259+
type: 'dropdown',
260+
label: 'Choose your preferred distance unit',
261+
options: ['km', 'mi'],
262+
allowCustom: false,
263+
isRequired: true,
264+
},
254265
climateTempWarm: {
255266
type: 'numberValue',
256267
label: 'Climate temp when pre-heating (whole number or .5)',

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import { confirm } from './lib/scriptable-utils'
4141
Script.complete()
4242
return resp
4343
} catch (error) {
44-
logError(JSON.stringify(error))
44+
logError(`main error ${JSON.stringify(error)}`)
4545
}
4646
}
4747
})()

0 commit comments

Comments
 (0)