Skip to content

Commit

Permalink
Merge pull request #159 from Hacksore/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Hacksore authored Sep 6, 2021
2 parents 027b2d2 + 36f21fa commit 561b845
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 145 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Run an install for all the dependencies, `npm install`
Now you can invoke the debug.ts script with `npm run debug`

## Documentation
Checkout out the [bluelinky-docs](https://hacksore.github.io/bluelinky-docs/) for more info.
Checkout out the [docs](https://bluelinky.readme.io) for more info.

Important information for login problems:
- 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.
Expand All @@ -80,6 +80,7 @@ The JSON file must respect [this format](https://github.com/neoPix/bluelinky-sta
- startCharge
- monthlyReport
- tripInfo
- EV: driveHistory
- EV: getChargeTargets
- EV: setChargeLimits

Expand Down
4 changes: 4 additions & 0 deletions __tests__/util.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ describe('Utility', () => {
expect(parseDate('20210118153031')).toEqual(new Date('2021-01-18:15:30:31'));
});

it('parseDate converts shortdate to date', () => {
expect(parseDate('20210117')).toEqual(new Date('2021-01-17:00:00:00'));
});

it('addTime can add minutes to a date', () => {
const start = new Date('2021-01-18:12:00:00');
expect(addMinutes(start, 30)).toEqual(new Date('2021-01-18:12:30:00'));
Expand Down
32 changes: 28 additions & 4 deletions debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Vehicle } from './src/vehicles/vehicle';
const apiCalls = [
{ name: 'exit', value: 'exit' },
{ name: 'start', value: 'start' },
{ name: 'vehicles', value: 'vehicles' },
{ name: 'odometer', value: 'odometer' },
{ name: 'stop', value: 'stop' },
{ name: 'status (on server cache)', value: 'status' },
Expand All @@ -21,12 +22,16 @@ const apiCalls = [
{ name: 'locate', value: 'locate' },
{ name: '[EU] monthly report', value: 'monthlyReport' },
{ name: '[EU] trip informations', value: 'tripInfo' },
{ name: '[EU][EV] get charge targets', value: 'getChargeTargets' },
{ name: '[EU][EV] set charge targets', value: 'setChargeTargets' },
{ name: '[EU] drive informations', value: 'drvInfo' },
{ name: '[EV] get charge targets', value: 'getChargeTargets' },
{ name: '[EV] set charge targets', value: 'setChargeTargets' },
{ name: '[EV] start charging', value: 'startCharge' },
{ name: '[EV] stop charging', value: 'stopCharge' },
];

let client: BlueLinky;
let vehicle;
const { username, password, vin, pin } = config;
const { username, password, pin } = config;

const onReadyHandler = <T extends Vehicle>(vehicles: T[]) => {
vehicle = vehicles[0];
Expand Down Expand Up @@ -61,7 +66,8 @@ const askForRegionInput = () => {
};

const createInstance = (region, brand) => {
const client = new BlueLinky({
// global abuse :)
client = new BlueLinky({
username,
password,
region,
Expand Down Expand Up @@ -104,6 +110,14 @@ async function performCommand(command) {
const odometer = await vehicle.odometer();
console.log('odometer', JSON.stringify(odometer, null, 2));
break;
case 'vehicles':
const vehicles = await client.getVehicles();
const response = vehicles.map(v => {
const { name, vin, nickname, regDate } = v.vehicleConfig;
return { name, vin, nickname, regDate };
});
console.log('vehicles', JSON.stringify(response, null, 2));
break;
case 'status':
const status = await vehicle.status({
refresh: false,
Expand Down Expand Up @@ -165,6 +179,10 @@ async function performCommand(command) {
const report = await vehicle.monthlyReport();
console.log('monthyReport : ' + JSON.stringify(report, null, 2));
break;
case 'drvInfo':
const info = await vehicle.driveHistory();
console.log('drvInfo : ', info);
break;
case 'tripInfo':
const currentYear = new Date().getFullYear();
const { year, month, day } = await inquirer
Expand Down Expand Up @@ -195,6 +213,12 @@ async function performCommand(command) {
const targets = await vehicle.getChargeTargets();
console.log('targets : ' + JSON.stringify(targets, null, 2));
break;
case 'startCharge':
await vehicle.startCharge();
break;
case 'stopCharge':
await vehicle.stopCharge();
break;
case 'setChargeTargets':
const { fast, slow } = await inquirer
.prompt([
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bluelinky",
"version": "7.4.1",
"version": "7.5.0",
"description": "An unofficial nodejs API wrapper for Hyundai bluelink",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
4 changes: 4 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export enum REGIONS {
EU = 'EU',
}

// ev stuffz
export type ChargeTarget = 50 | 60 | 70 | 80 | 90 | 100;
export const POSSIBLE_CHARGE_LIMIT_VALUES = [50, 60, 70, 80, 90, 100];

export const DEFAULT_VEHICLE_STATUS_OPTIONS: VehicleStatusOptions = {
refresh: false,
parsed: false,
Expand Down
8 changes: 7 additions & 1 deletion src/constants/canada.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export interface CanadianBrandEnvironment {
verifyAccountToken: string;
verifyPin: string;
verifyToken: string;
setChargeTarget: string;
stopCharge: string;
startCharge: string;
}
}

Expand All @@ -37,6 +40,9 @@ const getEndpoints = (baseUrl: string) => ({
unlock: `${baseUrl}/tods/api/drulck`,
start: `${baseUrl}/tods/api/evc/rfon`,
stop: `${baseUrl}/tods/api/evc/rfoff`,
startCharge: `${baseUrl}/tods/api/evc/rcstrt`,
stopCharge: `${baseUrl}/tods/api/evc/rcstp`,
setChargeTarget: `${baseUrl}/tods/api/evc/setsoc`,
locate: `${baseUrl}/tods/api/fndmcr`,
hornlight: `${baseUrl}/tods/api/hornlight`,
// System
Expand Down Expand Up @@ -78,4 +84,4 @@ export const getBrandEnvironment = (brand: Brand): CanadianBrandEnvironment => {
default:
throw new Error(`Constructor ${brand} is not managed.`);
}
};
};
31 changes: 31 additions & 0 deletions src/interfaces/european.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,34 @@ export interface EUPOIInformation {
placeid: string;
name: string;
}

export enum historyDrivingPeriod {
DAY = 0,
MONTH = 1,
ALL = 2
}

export enum historyCumulatedTypes {
TOTAL = 0,
AVERAGE = 1,
TODAY = 2
}

export interface EUDriveHistory {
period: historyCumulatedTypes,
consumption: {
total: number,
engine: number,
climate: number,
devices: number,
battery: number
},
regen: number,
distance: number
}

export interface EUDatedDriveHistory extends Omit<EUDriveHistory, 'period'> {
period: historyDrivingPeriod,
rawDate: string;
date: Date,
}
3 changes: 3 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ export const parseDate = (str: string): Date => {
const year = parseInt(str.substring(0, 4));
const month = parseInt(str.substring(4, 6));
const day = parseInt(str.substring(6, 8));
if (str.length <= 8) {
return new Date(year, month - 1, day);
}
const hour = parseInt(str.substring(8, 10));
const minute = parseInt(str.substring(10, 12));
const second = parseInt(str.substring(12, 14));
Expand Down
100 changes: 95 additions & 5 deletions src/vehicles/canadian.vehicle.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import got from 'got';
import logger from '../logger';

import { REGIONS, DEFAULT_VEHICLE_STATUS_OPTIONS } from '../constants';
import {
REGIONS,
DEFAULT_VEHICLE_STATUS_OPTIONS,
ChargeTarget,
POSSIBLE_CHARGE_LIMIT_VALUES,
} from '../constants';

import {
VehicleStartOptions,
Expand All @@ -12,11 +17,13 @@ import {
VehicleStatusOptions,
RawVehicleStatus,
FullVehicleStatus,
EVChargeModeTypes,
} from '../interfaces/common.interfaces';

import { Vehicle } from './vehicle';
import { celciusToTempCode, parseDate } from '../util';
import { CanadianController } from '../controllers/canadian.controller';
import { ManagedBluelinkyError } from '../tools/common.tools';

export default class CanadianVehicle extends Vehicle {
public region = REGIONS.CA;
Expand All @@ -40,7 +47,9 @@ export default class CanadianVehicle extends Vehicle {
};
logger.debug('Begin status request, polling car: ' + input.refresh);
try {
const endpoint = statusConfig.refresh ? this.controller.environment.endpoints.remoteStatus : this.controller.environment.endpoints.status;
const endpoint = statusConfig.refresh
? this.controller.environment.endpoints.remoteStatus
: this.controller.environment.endpoints.status;
const response = await this.request(endpoint, {});
const vehicleStatus = response.result?.status;

Expand Down Expand Up @@ -148,13 +157,19 @@ export default class CanadianVehicle extends Vehicle {
const airTemp = startConfig.airTempvalue;
// TODO: can we use getTempCode here from util?
if (airTemp != null) {
body.hvacInfo['airTemp'] = { value: celciusToTempCode(REGIONS.CA, airTemp), unit: 0, hvacTempType: 1 };
body.hvacInfo['airTemp'] = {
value: celciusToTempCode(REGIONS.CA, airTemp),
unit: 0,
hvacTempType: 1,
};
} else if ((startConfig.airCtrl ?? false) || (startConfig.defrost ?? false)) {
throw 'air temperature should be specified';
}

const preAuth = await this.getPreAuth();
const response = await this.request(this.controller.environment.endpoints.start, body, { pAuth: preAuth });
const response = await this.request(this.controller.environment.endpoints.start, body, {
pAuth: preAuth,
});

logger.debug(response);

Expand Down Expand Up @@ -197,6 +212,77 @@ export default class CanadianVehicle extends Vehicle {
}
}

/**
* Warning only works on EV vehicles
* @returns
*/
public async stopCharge(): Promise<void> {
logger.debug('Begin stopCharge');
const { stopCharge } = this.controller.environment.endpoints;
try {
const preAuth = await this.getPreAuth();
const response = await this.request(stopCharge, {
pin: this.controller.userConfig.pin,
pAuth: preAuth,
});
return response;
} catch (err) {
throw 'error: ' + err;
}
}

/**
* Warning only works on EV vehicles
* @returns
*/
public async startCharge(): Promise<void> {
logger.debug('Begin startCharge');
const { startCharge } = this.controller.environment.endpoints;
try {
const preAuth = await this.getPreAuth();
const response = await this.request(startCharge, {
pin: this.controller.userConfig.pin,
pAuth: preAuth,
});
return response;
} catch (err) {
throw 'error: ' + err;
}
}

/**
* Warning only works on EV vehicles
* @param limits
* @returns Promise<void>
*/
public async setChargeTargets(limits: { fast: ChargeTarget; slow: ChargeTarget }): Promise<void> {
logger.debug('Begin setChargeTarget');
if (
!POSSIBLE_CHARGE_LIMIT_VALUES.includes(limits.fast) ||
!POSSIBLE_CHARGE_LIMIT_VALUES.includes(limits.slow)
) {
throw new ManagedBluelinkyError(
`Charge target values are limited to ${POSSIBLE_CHARGE_LIMIT_VALUES.join(', ')}`
);
}

const { setChargeTarget } = this.controller.environment.endpoints;
try {
const preAuth = await this.getPreAuth();
const response = await this.request(setChargeTarget, {
pin: this.controller.userConfig.pin,
pAuth: preAuth,
tsoc: [
{ plugType: EVChargeModeTypes.FAST, level: limits.fast },
{ plugType: EVChargeModeTypes.SLOW, level: limits.slow },
],
});
return response;
} catch (err) {
throw 'error: ' + err;
}
}

// TODO: @Seb to take a look at doing this
public odometer(): Promise<VehicleOdometer | null> {
throw new Error('Method not implemented.');
Expand All @@ -206,7 +292,11 @@ export default class CanadianVehicle extends Vehicle {
logger.debug('Begin locate request');
try {
const preAuth = await this.getPreAuth();
const response = await this.request(this.controller.environment.endpoints.locate, {}, { pAuth: preAuth });
const response = await this.request(
this.controller.environment.endpoints.locate,
{},
{ pAuth: preAuth }
);
this._location = response.result as VehicleLocation;
return this._location;
} catch (err) {
Expand Down
Loading

0 comments on commit 561b845

Please sign in to comment.