Skip to content

Commit 0f04dd7

Browse files
authored
Merge pull request #112 from Hacksore/develop
2 parents e7947d8 + 440dfae commit 0f04dd7

24 files changed

Lines changed: 1317 additions & 623 deletions

README.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# bluelinky
22

3-
An unoffcial nodejs API wrapper for Hyundai BlueLink
3+
An unofficial nodejs API wrapper for Hyundai BlueLink
44

55
[![CI](https://img.shields.io/github/workflow/status/Hacksore/bluelinky/npm)](https://github.com/Hacksore/bluelinky/actions?query=workflow%3Anpm)
66
[![npm](https://img.shields.io/npm/v/bluelinky.svg)](https://www.npmjs.com/package/bluelinky)
@@ -18,6 +18,7 @@ const BlueLinky = require('bluelinky');
1818
const client = new BlueLinky({
1919
username: 'someguy@example.com',
2020
password: 'hunter1',
21+
brand: 'hyundai',
2122
region: 'US',
2223
pin: '1234'
2324
});
@@ -45,7 +46,8 @@ Ensure you have a `config.json` that matches the structure of the following, wit
4546
{
4647
"username": "email",
4748
"password": "password",
48-
"pin": "ping",
49+
"pin": "pin",
50+
"brand": "kia" or "hyundai",
4951
"vin": "vin"
5052
}
5153
```
@@ -56,12 +58,23 @@ Now you can invoke the debug.ts script with `npm run debug`
5658
## Documentation
5759
Checkout out the [bluelinky-docs](https://hacksore.github.io/bluelinky-docs/) for more info.
5860

61+
Important information for login problems:
62+
- If you experience login problems, please logout from the app on your phone and login again. You might need to ' upgrade ' your account to a generic Kia/Hyundai account, or create a new password or PIN.
63+
- After you migrated your Bluelink account to a generic Hyundai account, or your UVO account to a generic Kia account, make sure that both accounts have the same credentials (userid and password) to avoid confusion in logging in.
64+
5965
## Supported Features
6066
- Lock
6167
- Unlock
6268
- Start (with climate control)
6369
- Stop
64-
- Status
70+
- Status (full, parsed, cached)
71+
- odometer
72+
- location
73+
- startCharge
74+
- monthlyReport
75+
- tripInfo
76+
- EV: getChargeTargets
77+
- EV: setChargeLimits
6578

6679
## Supported Regions
6780
| [Regions](https://github.com/Hacksore/bluelinky/wiki/Regions)

__tests__/bluelinky.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ describe('BlueLinky', () => {
4848
username: 'someone@gmai.com',
4949
password: '123',
5050
pin: '1234',
51+
brand: 'hyundai',
5152
region: 'US',
5253
});
5354

@@ -79,6 +80,7 @@ describe('BlueLinky', () => {
7980
username: 'someone@gmail.com',
8081
password: 'hunter1',
8182
pin: '1234',
83+
brand: 'hyundai',
8284
region: 'US',
8385
});
8486

@@ -96,6 +98,7 @@ describe('BlueLinky', () => {
9698
username: 'someone@gmail.com',
9799
password: 'hunter1',
98100
pin: '1234',
101+
brand: 'hyundai',
99102
region: 'KR',
100103
});
101104
}).toThrowError('Your region is not supported yet.');
@@ -106,6 +109,7 @@ describe('BlueLinky', () => {
106109
username: 'someone@gmail.com',
107110
password: 'hunter1',
108111
pin: '1234',
112+
brand: 'hyundai',
109113
region: 'US',
110114
});
111115

@@ -119,6 +123,7 @@ describe('BlueLinky', () => {
119123
username: 'someone@gmail.com',
120124
password: 'hunter1',
121125
pin: '1234',
126+
brand: 'hyundai',
122127
region: 'US',
123128
});
124129

@@ -133,6 +138,7 @@ describe('BlueLinky', () => {
133138
username: 'someone@gmai.com',
134139
password: 'hunter1',
135140
pin: '1234',
141+
brand: 'hyundai',
136142
region: 'US',
137143
});
138144

__tests__/controller.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const getController = region => {
1818
username: 'testuser@gmail.com',
1919
password: 'test',
2020
region: 'US',
21+
brand: 'hyundai',
2122
autoLogin: true,
2223
pin: '1234',
2324
vin: '4444444444444',

__tests__/vehicle.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const getVehicle = (region: string) => {
4141
password: 'test',
4242
region: region,
4343
autoLogin: true,
44+
brand: 'hyundai',
4445
pin: '1234',
4546
vin: '4444444444444',
4647
vehicleId: undefined,

debug.ts

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import config from './config.json';
55
import BlueLinky from './src';
66
import inquirer from 'inquirer';
7+
import { Vehicle } from './src/vehicles/vehicle';
78

89
const apiCalls = [
910
{ name: 'exit', value: 'exit' },
@@ -18,12 +19,16 @@ const apiCalls = [
1819
{ name: 'lock', value: 'lock' },
1920
{ name: 'unlock', value: 'unlock' },
2021
{ name: 'locate', value: 'locate' },
22+
{ name: 'monthly report', value: 'monthlyReport' },
23+
{ name: 'trip informations', value: 'tripInfo' },
24+
{ name: '[EV] get charge targets', value: 'getChargeTargets' },
25+
{ name: '[EV] set charge targets', value: 'setChargeTargets' },
2126
];
2227

2328
let vehicle;
2429
const { username, password, vin, pin } = config;
2530

26-
const onReadyHandler = vehicles => {
31+
const onReadyHandler = <T extends Vehicle>(vehicles: T[]) => {
2732
vehicle = vehicles[0];
2833
askForCommandInput();
2934
};
@@ -37,23 +42,30 @@ const askForRegionInput = () => {
3742
message: 'What Region are you in?',
3843
choices: ['US', 'EU', 'CA'],
3944
},
45+
{
46+
type: 'list',
47+
name: 'brand',
48+
message: 'Which brand are you using?',
49+
choices: ['hyundai', 'kia'],
50+
}
4051
])
4152
.then(answers => {
4253
if (answers.command == 'exit') {
4354
return;
4455
} else {
4556
console.log(answers)
4657
console.log('Logging in...');
47-
createInstance(answers.region);
58+
createInstance(answers.region, answers.brand);
4859
}
4960
});
5061
};
5162

52-
const createInstance = region => {
63+
const createInstance = (region, brand) => {
5364
const client = new BlueLinky({
5465
username,
5566
password,
56-
region: region,
67+
region,
68+
brand,
5769
pin
5870
});
5971
client.on('ready', onReadyHandler);
@@ -99,6 +111,13 @@ async function performCommand(command) {
99111
});
100112
console.log('status : ' + JSON.stringify(status, null, 2));
101113
break;
114+
case 'statusU':
115+
const statusU = await vehicle.status({
116+
refresh: false,
117+
parsed: false,
118+
});
119+
console.log('status : ' + JSON.stringify(statusU, null, 2));
120+
break;
102121
case 'statusR':
103122
const statusR = await vehicle.status({
104123
refresh: true,
@@ -142,6 +161,37 @@ async function performCommand(command) {
142161
const unlockRes = await vehicle.unlock();
143162
console.log('unlock : ' + JSON.stringify(unlockRes, null, 2));
144163
break;
164+
case 'monthlyReport':
165+
const report = await vehicle.monthlyReport();
166+
console.log('monthyReport : ' + JSON.stringify(report, null, 2));
167+
break;
168+
case 'tripInfo':
169+
const trips = await vehicle.tripInfo();
170+
console.log('trips : ' + JSON.stringify(trips, null, 2));
171+
break;
172+
case 'getChargeTargets':
173+
const targets = await vehicle.getChargeTargets();
174+
console.log('targets : ' + JSON.stringify(targets, null, 2));
175+
break;
176+
case 'setChargeTargets':
177+
const { fast, slow } = await inquirer
178+
.prompt([
179+
{
180+
type: 'list',
181+
name: 'fast',
182+
message: 'What fast charge limit do you which to set?',
183+
choices: [50, 60, 70, 80, 90, 100],
184+
},
185+
{
186+
type: 'list',
187+
name: 'slow',
188+
message: 'What slow charge limit do you which to set?',
189+
choices: [50, 60, 70, 80, 90, 100],
190+
}
191+
]);
192+
await vehicle.setChargeTargets({ fast, slow });
193+
console.log('targets : OK');
194+
break;
145195
}
146196

147197
askForCommandInput();

package-lock.json

Lines changed: 8 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bluelinky",
3-
"version": "6.0.1",
3+
"version": "7.0.0",
44
"description": "",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
@@ -18,8 +18,9 @@
1818
"author": "Hacksore",
1919
"license": "MIT",
2020
"dependencies": {
21+
"date-fns": "^2.19.0",
2122
"got": "^9.6.0",
22-
"push-receiver": "^2.1.0",
23+
"push-receiver": "^2.1.1",
2324
"tough-cookie": "^4.0.0",
2425
"url": "^0.11.0",
2526
"winston": "^3.3.3"

src/constants.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// moved all the US constants to its own file, we can use this file for shared constants
2-
import { CA_ENDPOINTS } from './constants/canada';
3-
import { EU_ENDPOINTS } from './constants/europe';
2+
import { getBrandEnvironment as getCABrandEnvironment, CanadianBrandEnvironment } from './constants/canada';
3+
import { getBrandEnvironment as getEUBrandEnvironment, EuropeanBrandEnvironment } from './constants/europe';
44

5-
import { VehicleStatusOptions } from './interfaces/common.interfaces';
5+
import { Brand, VehicleStatusOptions } from './interfaces/common.interfaces';
66

77
export const ALL_ENDPOINTS = {
8-
CA: CA_ENDPOINTS,
9-
EU: EU_ENDPOINTS,
8+
CA: (brand: Brand): CanadianBrandEnvironment['endpoints'] => getCABrandEnvironment(brand).endpoints,
9+
EU: (brand: Brand): EuropeanBrandEnvironment['endpoints'] => getEUBrandEnvironment(brand).endpoints,
1010
};
1111

1212
export const GEN2 = 2;

src/constants/america.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
1-
//TODO: Someone needs to figure out the Kia endpoints
2-
// we can then make a fork easier to maintain
1+
import { Brand } from '../interfaces/common.interfaces';
32

4-
export const API_HOST = 'api.telematics.hyundaiusa.com';
3+
export interface AmericaBrandEnvironment {
4+
brand: Brand;
5+
host: string;
6+
baseUrl: string;
7+
clientId: string;
8+
clientSecret: string;
9+
}
510

6-
export const BASE_URL = `https://${API_HOST}`;
7-
export const CLIENT_ID = '815c046afaa4471aa578827ad546cc76';
8-
export const CLIENT_SECRET = 'GXZveJJAVTehh/OtakM3EQ==';
11+
const getHyundaiEnvironment = (): AmericaBrandEnvironment => {
12+
const host = 'api.telematics.hyundaiusa.com';
13+
const baseUrl = `https://${host}`;
14+
return {
15+
brand: 'hyundai',
16+
host,
17+
baseUrl,
18+
clientId: '815c046afaa4471aa578827ad546cc76',
19+
clientSecret: 'GXZveJJAVTehh/OtakM3EQ==',
20+
};
21+
};
22+
23+
export const getBrandEnvironment = (brand: Brand): AmericaBrandEnvironment => {
24+
switch (brand) {
25+
case 'hyundai':
26+
return Object.freeze(getHyundaiEnvironment());
27+
default:
28+
throw new Error(`Constructor ${brand} is not managed.`);
29+
}
30+
};

0 commit comments

Comments
 (0)