From 3a3747f70f9c82c2fba327ce6fe6adc31ad75993 Mon Sep 17 00:00:00 2001 From: Kasper Guldmann Nielsen Date: Sun, 2 Oct 2022 01:02:46 +0200 Subject: [PATCH 1/2] Add support for getChargeSchedule --- src/interfaces/common.interfaces.ts | 924 +++++++++++---------- src/vehicles/european.vehicle.ts | 1198 ++++++++++++++------------- 2 files changed, 1121 insertions(+), 1001 deletions(-) diff --git a/src/interfaces/common.interfaces.ts b/src/interfaces/common.interfaces.ts index 9b37893..4a11ef4 100644 --- a/src/interfaces/common.interfaces.ts +++ b/src/interfaces/common.interfaces.ts @@ -1,509 +1,597 @@ -import { REGION } from '../constants'; +import { ChargeTarget, REGION } from '../constants'; export type Brand = 'kia' | 'hyundai'; // config export interface BlueLinkyConfig { - username: string | undefined; - password: string | undefined; - region: REGION | undefined; - brand: Brand; - autoLogin?: boolean; - pin: string | undefined; - vin?: string | undefined; - vehicleId?: string | undefined; + username: string | undefined; + password: string | undefined; + region: REGION | undefined; + brand: Brand; + autoLogin?: boolean; + pin: string | undefined; + vin?: string | undefined; + vehicleId?: string | undefined; } export interface BluelinkVehicle { - name: string; - vin: string; - type: string; + name: string; + vin: string; + type: string; } export interface Session { - accessToken?: string; - refreshToken?: string; - controlToken?: string; - deviceId?: string; - tokenExpiresAt: number; - controlTokenExpiresAt?: number; + accessToken?: string; + refreshToken?: string; + controlToken?: string; + deviceId?: string; + tokenExpiresAt: number; + controlTokenExpiresAt?: number; } export enum EVPlugTypes { - UNPLUGED = 0, - FAST = 1, - PORTABLE = 2, - STATION = 3 + UNPLUGED = 0, + FAST = 1, + PORTABLE = 2, + STATION = 3 } export enum EVChargeModeTypes { - FAST = 0, - SLOW = 1, + FAST = 0, + SLOW = 1, } // Status remapped export interface VehicleStatus { - engine: { - ignition: boolean; - batteryCharge?: number; - charging?: boolean; - timeToFullCharge?: unknown; - range: number; - rangeGas?: number; - rangeEV?: number; - plugedTo? : EVPlugTypes; - estimatedCurrentChargeDuration?: number; - estimatedFastChargeDuration?: number; - estimatedPortableChargeDuration?: number; - estimatedStationChargeDuration?: number; - batteryCharge12v?: number; - batteryChargeHV?: number; - accessory: boolean; - }; - climate: { - active: boolean; - steeringwheelHeat: boolean; - sideMirrorHeat: boolean; - rearWindowHeat: boolean; - temperatureSetpoint: number; - temperatureUnit: number; - defrost: boolean; - }; - chassis: { - hoodOpen: boolean; - trunkOpen: boolean; - locked: boolean; - openDoors: { - frontRight: boolean; - frontLeft: boolean; - backLeft: boolean; - backRight: boolean; + engine: { + ignition: boolean; + batteryCharge?: number; + charging?: boolean; + timeToFullCharge?: unknown; + range: number; + rangeGas?: number; + rangeEV?: number; + plugedTo?: EVPlugTypes; + estimatedCurrentChargeDuration?: number; + estimatedFastChargeDuration?: number; + estimatedPortableChargeDuration?: number; + estimatedStationChargeDuration?: number; + batteryCharge12v?: number; + batteryChargeHV?: number; + accessory: boolean; }; - tirePressureWarningLamp: { - rearLeft: boolean; - frontLeft: boolean; - frontRight: boolean; - rearRight: boolean; - all: boolean; + climate: { + active: boolean; + steeringwheelHeat: boolean; + sideMirrorHeat: boolean; + rearWindowHeat: boolean; + temperatureSetpoint: number; + temperatureUnit: number; + defrost: boolean; + }; + chassis: { + hoodOpen: boolean; + trunkOpen: boolean; + locked: boolean; + openDoors: { + frontRight: boolean; + frontLeft: boolean; + backLeft: boolean; + backRight: boolean; + }; + tirePressureWarningLamp: { + rearLeft: boolean; + frontLeft: boolean; + frontRight: boolean; + rearRight: boolean; + all: boolean; + }; }; - }; - lastupdate: Date|null + lastupdate: Date | null } // TODO: fix/update export interface FullVehicleStatus { - vehicleLocation: { - coord: { lat: number; lon: number; alt: number; type: number }; - head: number; - speed: { value: number; unit: number }; - accuracy: { hdop: number; pdop: number }; - time: string; - }; - odometer: { value: number, unit: number }; - vehicleStatus: { - time: string; - airCtrlOn: boolean; - engine: boolean; + vehicleLocation: { + coord: { lat: number; lon: number; alt: number; type: number }; + head: number; + speed: { value: number; unit: number }; + accuracy: { hdop: number; pdop: number }; + time: string; + }; + odometer: { value: number, unit: number }; + vehicleStatus: { + time: string; + airCtrlOn: boolean; + engine: boolean; + doorLock: boolean; + doorOpen: { frontRight: number; frontLeft: number; backLeft: number; backRight: number }; + trunkOpen: boolean; + airTemp: { unit: number; hvacTempType: number; value: string }; + defrost: boolean; + acc: boolean; + ign3: boolean; + hoodOpen: boolean; + transCond: boolean; + steerWheelHeat: number; + sideBackWindowHeat: number; + tirePressureLamp: { + tirePressureWarningLampAll: number; + tirePressureWarningLampFL: number; + tirePressureWarningLampFR: number; + tirePressureWarningLampRL: number; + tirePressureWarningLampRR: number; + }; + battery: { batSoc: number; batState: number; }; + evStatus: { + batteryCharge: boolean; + batteryStatus: number; + batteryPlugin: number; + remainTime2: { + etc1: { value: number; unit: number; }; + etc2: { value: number; unit: number; }; + etc3: { value: number; unit: number; }; + atc: { value: number; unit: number; }; + }; + drvDistance: [ + { + rangeByFuel: { + gasModeRange: { value: number; unit: number }; + evModeRange: { value: number; unit: number }; + totalAvailableRange: { value: number; unit: number }; + }; + type: number; + } + ]; + // "reservChargeInfos": { + // "reservChargeInfo": { + // "reservChargeInfoDetail": { + // "reservInfo": { + // "day": [ + // 1, + // 2, + // 3, + // 4, + // 5 + // ], + // "time": { + // "time": "0800", + // "timeSection": 0 + // } + // }, + // "reservChargeSet": true, + // "reservFatcSet": { + // "defrost": false, + // "airTemp": { + // "value": "00H", + // "unit": 0, + // "hvacTempType": 1 + // }, + // "airCtrl": 0, + // "heating1": 0 + // } + // } + // }, + // "offpeakPowerInfo": { + // "offPeakPowerTime1": { + // "starttime": { + // "time": "1200", + // "timeSection": 0 + // }, + // "endtime": { + // "time": "1200", + // "timeSection": 0 + // } + // }, + // "offPeakPowerFlag": 1 + // }, + // "reserveChargeInfo2": { + // "reservChargeInfoDetail": { + // "reservInfo": { + // "day": [ + // 9 + // ], + // "time": { + // "time": "1200", + // "timeSection": 0 + // } + // }, + // "reservChargeSet": false, + // "reservFatcSet": { + // "defrost": false, + // "airTemp": { + // "value": "00H", + // "unit": 0, + // "hvacTempType": 1 + // }, + // "airCtrl": 0, + // "heating1": 0 + // } + // } + // }, + // "reservFlag": 0, + // "ect": { + // "start": { + // "day": 9, + // "time": { + // "time": "1200", + // "timeSection": 0 + // } + // }, + // "end": { + // "day": 9, + // "time": { + // "time": "1200", + // "timeSection": 0 + // } + // } + // }, + // "targetSOClist": [ + // { + // "targetSOClevel": 90, + // "dte": { + // "rangeByFuel": { + // "evModeRange": { + // "value": 392, + // "unit": 1 + // }, + // "totalAvailableRange": { + // "value": 392, + // "unit": 1 + // } + // }, + // "type": 2 + // }, + // "plugType": 0 + // }, + // { + // "targetSOClevel": 80, + // "dte": { + // "rangeByFuel": { + // "evModeRange": { + // "value": 345, + // "unit": 1 + // }, + // "totalAvailableRange": { + // "value": 345, + // "unit": 1 + // } + // }, + // "type": 2 + // }, + // "plugType": 1 + // } + // ] + // } + }; + } +} + +// TODO: remove +// ======= +// Rough mapping of the raw status that might no be the same for all regions + +export interface RawVehicleStatus { + lastStatusDate: string; + dateTime: string; + acc: boolean; + trunkOpen: boolean; doorLock: boolean; + defrostStatus: string; + transCond: boolean; + doorLockStatus: string; doorOpen: { frontRight: number; frontLeft: number; backLeft: number; backRight: number }; - trunkOpen: boolean; + airCtrlOn: boolean; + airTempUnit: string; airTemp: { unit: number; hvacTempType: number; value: string }; - defrost: boolean; - acc: boolean; + battery: { + batSignalReferenceValue: unknown; + batSoc: number; + batState: number; + sjbDeliveryMode: number; + }; ign3: boolean; + ignitionStatus: string; + lowFuelLight: boolean; + sideBackWindowHeat: number; + dte: { unit: number; value: number }; + engine: boolean; + defrost: boolean; hoodOpen: boolean; - transCond: boolean; + airConditionStatus: string; steerWheelHeat: number; - sideBackWindowHeat: number; tirePressureLamp: { - tirePressureWarningLampAll: number; - tirePressureWarningLampFL: number; - tirePressureWarningLampFR: number; - tirePressureWarningLampRL: number; - tirePressureWarningLampRR: number; + tirePressureWarningLampRearLeft: number; + tirePressureWarningLampFrontLeft: number; + tirePressureWarningLampFrontRight: number; + tirePressureWarningLampAll: number; + tirePressureWarningLampRearRight: number; }; - battery: { batSoc: number; batState: number; }; + trunkOpenStatus: string; evStatus: { - batteryCharge: boolean; - batteryStatus: number; - batteryPlugin: number; - remainTime2: { - etc1: { value: number; unit: number; }; - etc2: { value: number; unit: number; }; - etc3: { value: number; unit: number; }; - atc: { value: number; unit: number; }; - }; - drvDistance: [ - { - rangeByFuel: { - gasModeRange: { value: number; unit: number }; - evModeRange: { value: number; unit: number }; - totalAvailableRange: { value: number; unit: number }; - }; - type: number; - } - ]; - // "reservChargeInfos": { - // "reservChargeInfo": { - // "reservChargeInfoDetail": { - // "reservInfo": { - // "day": [ - // 1, - // 2, - // 3, - // 4, - // 5 - // ], - // "time": { - // "time": "0800", - // "timeSection": 0 - // } - // }, - // "reservChargeSet": true, - // "reservFatcSet": { - // "defrost": false, - // "airTemp": { - // "value": "00H", - // "unit": 0, - // "hvacTempType": 1 - // }, - // "airCtrl": 0, - // "heating1": 0 - // } - // } - // }, - // "offpeakPowerInfo": { - // "offPeakPowerTime1": { - // "starttime": { - // "time": "1200", - // "timeSection": 0 - // }, - // "endtime": { - // "time": "1200", - // "timeSection": 0 - // } - // }, - // "offPeakPowerFlag": 1 - // }, - // "reserveChargeInfo2": { - // "reservChargeInfoDetail": { - // "reservInfo": { - // "day": [ - // 9 - // ], - // "time": { - // "time": "1200", - // "timeSection": 0 - // } - // }, - // "reservChargeSet": false, - // "reservFatcSet": { - // "defrost": false, - // "airTemp": { - // "value": "00H", - // "unit": 0, - // "hvacTempType": 1 - // }, - // "airCtrl": 0, - // "heating1": 0 - // } - // } - // }, - // "reservFlag": 0, - // "ect": { - // "start": { - // "day": 9, - // "time": { - // "time": "1200", - // "timeSection": 0 - // } - // }, - // "end": { - // "day": 9, - // "time": { - // "time": "1200", - // "timeSection": 0 - // } - // } - // }, - // "targetSOClist": [ - // { - // "targetSOClevel": 90, - // "dte": { - // "rangeByFuel": { - // "evModeRange": { - // "value": 392, - // "unit": 1 - // }, - // "totalAvailableRange": { - // "value": 392, - // "unit": 1 - // } - // }, - // "type": 2 - // }, - // "plugType": 0 - // }, - // { - // "targetSOClevel": 80, - // "dte": { - // "rangeByFuel": { - // "evModeRange": { - // "value": 345, - // "unit": 1 - // }, - // "totalAvailableRange": { - // "value": 345, - // "unit": 1 - // } - // }, - // "type": 2 - // }, - // "plugType": 1 - // } - // ] - // } + batteryCharge: boolean; + batteryStatus: number; + batteryPlugin: number; + remainTime2: { + etc1: { value: number; unit: number }; + etc2: { value: number; unit: number }; + etc3: { value: number; unit: number }; + atc: { value: number; unit: number }; + }; + drvDistance: [ + { + rangeByFuel: { + gasModeRange: { value: number; unit: number }; + evModeRange: { value: number; unit: number }; + totalAvailableRange: { value: number; unit: number }; + }; + type: number; + } + ]; }; - } -} - -// TODO: remove -// ======= -// Rough mapping of the raw status that might no be the same for all regions - -export interface RawVehicleStatus { - lastStatusDate: string; - dateTime: string; - acc: boolean; - trunkOpen: boolean; - doorLock: boolean; - defrostStatus: string; - transCond: boolean; - doorLockStatus: string; - doorOpen: { frontRight: number; frontLeft: number; backLeft: number; backRight: number }; - airCtrlOn: boolean; - airTempUnit: string; - airTemp: { unit: number; hvacTempType: number; value: string }; - battery: { - batSignalReferenceValue: unknown; - batSoc: number; - batState: number; - sjbDeliveryMode: number; - }; - ign3: boolean; - ignitionStatus: string; - lowFuelLight: boolean; - sideBackWindowHeat: number; - dte: { unit: number; value: number }; - engine: boolean; - defrost: boolean; - hoodOpen: boolean; - airConditionStatus: string; - steerWheelHeat: number; - tirePressureLamp: { - tirePressureWarningLampRearLeft: number; - tirePressureWarningLampFrontLeft: number; - tirePressureWarningLampFrontRight: number; - tirePressureWarningLampAll: number; - tirePressureWarningLampRearRight: number; - }; - trunkOpenStatus: string; - evStatus: { - batteryCharge: boolean; - batteryStatus: number; - batteryPlugin: number; - remainTime2: { - etc1: { value: number; unit: number }; - etc2: { value: number; unit: number }; - etc3: { value: number; unit: number }; - atc: { value: number; unit: number }; + remoteIgnition: boolean; + seatHeaterVentInfo: unknown; + sleepModeCheck: boolean; + lampWireStatus: { + headLamp: unknown; + stopLamp: unknown; + turnSignalLamp: unknown; }; - drvDistance: [ - { - rangeByFuel: { - gasModeRange: { value: number; unit: number }; - evModeRange: { value: number; unit: number }; - totalAvailableRange: { value: number; unit: number }; - }; - type: number; - } - ]; - }; - remoteIgnition: boolean; - seatHeaterVentInfo: unknown; - sleepModeCheck: boolean; - lampWireStatus: { - headLamp: unknown; - stopLamp: unknown; - turnSignalLamp: unknown; - }; - windowOpen: unknown; - engineRuntime: unknown; + windowOpen: unknown; + engineRuntime: unknown; } // Vehicle Info export interface VehicleInfo { - vehicleId: string; - nickName: string; - modelCode: string; - modelName: string; - modelYear: string; - fuelKindCode: string; - trim: string; - engine: string; - exteriorColor: string; - dtcCount: number; - subscriptionStatus: string; - subscriptionEndDate: string; - overviewMessage: string; - odometer: number; - odometerUnit: number; - defaultVehicle: boolean; - enrollmentStatus: string; - genType: string; - transmissionType: string; - vin: string; + vehicleId: string; + nickName: string; + modelCode: string; + modelName: string; + modelYear: string; + fuelKindCode: string; + trim: string; + engine: string; + exteriorColor: string; + dtcCount: number; + subscriptionStatus: string; + subscriptionEndDate: string; + overviewMessage: string; + odometer: number; + odometerUnit: number; + defaultVehicle: boolean; + enrollmentStatus: string; + genType: string; + transmissionType: string; + vin: string; } export interface VehicleFeatureEntry { - category: string; - features: [ - { - featureName: string; - features: [ + category: string; + features: [ { - subFeatureName: string; - subFeatureValue: string; + featureName: string; + features: [ + { + subFeatureName: string; + subFeatureValue: string; + } + ]; } - ]; - } - ]; + ]; } // Location export interface VehicleLocation { - latitude: number; - longitude: number; - altitude: number; - speed: { - unit: number; - value: number; - }; - heading: number; + latitude: number; + longitude: number; + altitude: number; + speed: { + unit: number; + value: number; + }; + heading: number; } export interface VehicleOdometer { - unit: number; - value: number; + unit: number; + value: number; } export interface VehicleStatusOptions { - refresh: boolean; - parsed: boolean; + refresh: boolean; + parsed: boolean; } // VEHICLE COMMANDS ///////////////////////////////////////////// export interface VehicleCommandResponse { - responseCode: number; // 0 is success - responseDesc: string; + responseCode: number; // 0 is success + responseDesc: string; } export interface VehicleStartOptions { - airCtrl?: boolean | string; - igniOnDuration: number; - airTempvalue?: number; - defrost?: boolean | string; - heating1?: boolean | string; + airCtrl?: boolean | string; + igniOnDuration: number; + airTempvalue?: number; + defrost?: boolean | string; + heating1?: boolean | string; } export interface VehicleClimateOptions { - defrost: boolean; - windscreenHeating: boolean; - temperature: number; - unit: string; + defrost: boolean; + windscreenHeating: boolean; + temperature: number; + unit: string; } export interface VehicleRegisterOptions { - nickname: string; - name: string; - vin: string; - regDate: string; - brandIndicator: string; - regId: string; - id: string; - generation: string; + nickname: string; + name: string; + vin: string; + regDate: string; + brandIndicator: string; + regId: string; + id: string; + generation: string; } export type DeepPartial = { - [P in keyof T]?: DeepPartial; + [P in keyof T]?: DeepPartial; }; export interface VehicleMonthlyReport { - start: string; // format YYYYMMDD, eg: 20210210 - end: string; // format YYYYMMDD, eg: 20210312 - driving: { - distance: number; - startCount: number; - durations: { - drive: number; - idle: number; - } - }, - breakdown: { - ecuIdx: string; - ecuStatus: string; - }[], - vehicleStatus: { - tpms: boolean; - tirePressure: { - all: boolean; + start: string; // format YYYYMMDD, eg: 20210210 + end: string; // format YYYYMMDD, eg: 20210312 + driving: { + distance: number; + startCount: number; + durations: { + drive: number; + idle: number; + } + }, + breakdown: { + ecuIdx: string; + ecuStatus: string; + }[], + vehicleStatus: { + tpms: boolean; + tirePressure: { + all: boolean; + } } - } } export interface VehicleTargetSOC { - type: EVChargeModeTypes; - distance: number; - targetLevel: number; + type: EVChargeModeTypes; + distance: number; + targetLevel: number; } export interface VehicleMonthTrip { - days: Array<{ dayRaw: string; date?: Date; tripsCount: number }>; - durations: { - drive: number; - idle: number; - }; - speed: { - avg: number; - max: number; - }; - distance: number; + days: Array<{ dayRaw: string; date?: Date; tripsCount: number }>; + durations: { + drive: number; + idle: number; + }; + speed: { + avg: number; + max: number; + }; + distance: number; } export interface VehicleDayTrip { - dayRaw: string; - tripsCount: number; - distance: number; - durations: { - drive: number; - idle: number; - }; - speed: { - avg: number; - max: number; - }; - trips: { - timeRaw: string; - start: Date; - end: Date; + dayRaw: string; + tripsCount: number; + distance: number; durations: { - drive: number; - idle: number; + drive: number; + idle: number; }; speed: { - avg: number; - max: number; + avg: number; + max: number; }; - distance: number; - }[]; + trips: { + timeRaw: string; + start: Date; + end: Date; + durations: { + drive: number; + idle: number; + }; + speed: { + avg: number; + max: number; + }; + distance: number; + }[]; +} + +export const enum OffPeakPowerFlag { + OffPeakPreferred = 1, + OffPeakOnly = 2, +} + +export const enum RangeUnit { + Kilometers = 1, + //TODO determine enum value for miles +} + +export interface Range { + value: number, + unit: RangeUnit, +} + +export interface SocTarget { + targetSOClevel: ChargeTarget, + plugType: EVChargeModeTypes, + dte?: { + rangeByFuel: { + evModeRange: Range, + totalAvailableRange: Range + } + type: number //TODO determine the meaning of this + } +} + +export const enum Weekday { + Monday = 1, + Tyesday = 2, + Wednesday = 3, + Thursday = 4, + Friday = 5, + Saturday = 6, + Sunday = 0, + + Unknown = 9 +} +/** AM or PM */ +export const enum TimeSection { + AM = 0, + PM = 1 +} + +/** A time of day, in the vehicle's time zone. */ +export interface Time { + /** String of 4 digits, '1200' through '1259' and '0100' through '1159' */ + time: string, + timeSection: TimeSection +} + +export interface ReservChargeInfoDetail { + reservInfo: { + day: Weekday[], + time: Time, + } + reservChargeSet: boolean, + reservFatcSet: { + defrost: boolean, + airTemp: { //TODO decode the deeper meaning of this. + value: string, + unit: number, + hvacTempType: number + }, + airCtrl: number, + heating1: number + + } +} + +export interface ReservationCharge { + reservChargeInfo: { reservChargeInfoDetail: ReservChargeInfoDetail }, + reserveChargeInfo2: { reservChargeInfoDetail: ReservChargeInfoDetail }, + offpeakPowerInfo: { + offPeakPowerTime1: { + starttime: Time, + endtime: Time + }, + offPeakPowerFlag: OffPeakPowerFlag + }, + reservFlag: number, //TODO determine the meaning of this + ect: { + start: { day: Weekday, time: Time }, + end: { day: Weekday, time: Time } + }, + targetSOClist: SocTarget[] } \ No newline at end of file diff --git a/src/vehicles/european.vehicle.ts b/src/vehicles/european.vehicle.ts index feb334d..98fe14c 100644 --- a/src/vehicles/european.vehicle.ts +++ b/src/vehicles/european.vehicle.ts @@ -1,25 +1,26 @@ import { - REGIONS, - DEFAULT_VEHICLE_STATUS_OPTIONS, - POSSIBLE_CHARGE_LIMIT_VALUES, - ChargeTarget, + REGIONS, + DEFAULT_VEHICLE_STATUS_OPTIONS, + POSSIBLE_CHARGE_LIMIT_VALUES, + ChargeTarget, } from '../constants'; import { - VehicleStatus, - FullVehicleStatus, - VehicleOdometer, - VehicleLocation, - VehicleClimateOptions, - VehicleRegisterOptions, - VehicleStatusOptions, - RawVehicleStatus, - EVPlugTypes, - VehicleMonthlyReport, - DeepPartial, - VehicleTargetSOC, - EVChargeModeTypes, - VehicleDayTrip, - VehicleMonthTrip, + VehicleStatus, + FullVehicleStatus, + VehicleOdometer, + VehicleLocation, + VehicleClimateOptions, + VehicleRegisterOptions, + VehicleStatusOptions, + RawVehicleStatus, + EVPlugTypes, + VehicleMonthlyReport, + DeepPartial, + VehicleTargetSOC, + EVChargeModeTypes, + VehicleDayTrip, + VehicleMonthTrip, + ReservationCharge, } from '../interfaces/common.interfaces'; import logger from '../logger'; @@ -28,605 +29,636 @@ import { EuropeanController } from '../controllers/european.controller'; import { celciusToTempCode, tempCodeToCelsius, parseDate, addMinutes } from '../util'; import { manageBluelinkyError, ManagedBluelinkyError } from '../tools/common.tools'; import { - EUDatedDriveHistory, - EUDriveHistory, - EUPOIInformation, - historyDrivingPeriod, + EUDatedDriveHistory, + EUDriveHistory, + EUPOIInformation, + historyDrivingPeriod, } from '../interfaces/european.interfaces'; import got from 'got'; export default class EuropeanVehicle extends Vehicle { - public region = REGIONS.EU; - public serverRates: { - max: number; - current: number; - reset?: Date; - updatedAt?: Date; - } = { - max: -1, - current: -1, - }; - - constructor(public vehicleConfig: VehicleRegisterOptions, public controller: EuropeanController) { - super(vehicleConfig, controller); - logger.debug(`EU Vehicle ${this.vehicleConfig.id} created`); - } - - public async start(config: VehicleClimateOptions): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/temperature`, { - body: { - action: 'start', - hvacType: 0, - options: { - defrost: config.defrost, - heating1: config.windscreenHeating ? 1 : 0, - }, - tempCode: celciusToTempCode(REGIONS.EU, config.temperature), - unit: config.unit, - }, - }) - ); - logger.info(`Climate started for vehicle ${this.vehicleConfig.id}`); - return response.body; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.start'); - } - } - - public async stop(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/temperature`, { - body: { - action: 'stop', - hvacType: 0, - options: { - defrost: true, - heating1: 1, - }, - tempCode: '10H', - unit: 'C', - }, - }) - ); - logger.info(`Climate stopped for vehicle ${this.vehicleConfig.id}`); - return response.body; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.stop'); - } - } - - public async lock(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/door`, { - body: { - action: 'close', - deviceId: this.controller.session.deviceId, - }, - }) - ); - if (response.statusCode === 200) { - logger.debug(`Vehicle ${this.vehicleConfig.id} locked`); - return 'Lock successful'; - } - return 'Something went wrong!'; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.lock'); + public region = REGIONS.EU; + public serverRates: { + max: number; + current: number; + reset?: Date; + updatedAt?: Date; + } = { + max: -1, + current: -1, + }; + + constructor(public vehicleConfig: VehicleRegisterOptions, public controller: EuropeanController) { + super(vehicleConfig, controller); + logger.debug(`EU Vehicle ${this.vehicleConfig.id} created`); } - } - - public async unlock(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/door`, { - body: { - action: 'open', - deviceId: this.controller.session.deviceId, - }, - }) - ); - - if (response.statusCode === 200) { - logger.debug(`Vehicle ${this.vehicleConfig.id} unlocked`); - return 'Unlock successful'; - } - - return 'Something went wrong!'; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.unlock'); + + public async start(config: VehicleClimateOptions): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/temperature`, { + body: { + action: 'start', + hvacType: 0, + options: { + defrost: config.defrost, + heating1: config.windscreenHeating ? 1 : 0, + }, + tempCode: celciusToTempCode(REGIONS.EU, config.temperature), + unit: config.unit, + }, + }) + ); + logger.info(`Climate started for vehicle ${this.vehicleConfig.id}`); + return response.body; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.start'); + } } - } - - public async fullStatus(input: VehicleStatusOptions): Promise { - const statusConfig = { - ...DEFAULT_VEHICLE_STATUS_OPTIONS, - ...input, - }; - - const http = await this.controller.getVehicleHttpService(); - - try { - const cachedResponse = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status/latest`) - ); - - const fullStatus = cachedResponse.body.resMsg.vehicleStatusInfo; - - if (statusConfig.refresh) { - const statusResponse = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status`) - ); - fullStatus.vehicleStatus = statusResponse.body.resMsg; - - const locationResponse = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location`) - ); - fullStatus.vehicleLocation = locationResponse.body.resMsg.gpsDetail; - } - - this._fullStatus = fullStatus; - return this._fullStatus; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.fullStatus'); + + public async stop(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/temperature`, { + body: { + action: 'stop', + hvacType: 0, + options: { + defrost: true, + heating1: 1, + }, + tempCode: '10H', + unit: 'C', + }, + }) + ); + logger.info(`Climate stopped for vehicle ${this.vehicleConfig.id}`); + return response.body; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.stop'); + } } - } - - public async status( - input: VehicleStatusOptions - ): Promise { - const statusConfig = { - ...DEFAULT_VEHICLE_STATUS_OPTIONS, - ...input, - }; - - const http = await this.controller.getVehicleHttpService(); - - try { - const cacheString = statusConfig.refresh ? '' : '/latest'; - - const response = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status${cacheString}`) - ); - - // handles refreshing data - const vehicleStatus = statusConfig.refresh - ? response.body.resMsg - : response.body.resMsg.vehicleStatusInfo.vehicleStatus; - - const parsedStatus: VehicleStatus = { - chassis: { - hoodOpen: vehicleStatus?.hoodOpen, - trunkOpen: vehicleStatus?.trunkOpen, - locked: vehicleStatus.doorLock, - openDoors: { - frontRight: !!vehicleStatus?.doorOpen?.frontRight, - frontLeft: !!vehicleStatus?.doorOpen?.frontLeft, - backLeft: !!vehicleStatus?.doorOpen?.backLeft, - backRight: !!vehicleStatus?.doorOpen?.backRight, - }, - tirePressureWarningLamp: { - rearLeft: !!vehicleStatus?.tirePressureLamp?.tirePressureLampRL, - frontLeft: !!vehicleStatus?.tirePressureLamp?.tirePressureLampFL, - frontRight: !!vehicleStatus?.tirePressureLamp?.tirePressureLampFR, - rearRight: !!vehicleStatus?.tirePressureLamp?.tirePressureLampRR, - all: !!vehicleStatus?.tirePressureLamp?.tirePressureWarningLampAll, - }, - }, - climate: { - active: vehicleStatus?.airCtrlOn, - steeringwheelHeat: !!vehicleStatus?.steerWheelHeat, - sideMirrorHeat: false, - rearWindowHeat: !!vehicleStatus?.sideBackWindowHeat, - defrost: vehicleStatus?.defrost, - temperatureSetpoint: tempCodeToCelsius(REGIONS.EU, vehicleStatus?.airTemp?.value), - temperatureUnit: vehicleStatus?.airTemp?.unit, - }, - engine: { - ignition: vehicleStatus.engine, - accessory: vehicleStatus?.acc, - rangeGas: - vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.gasModeRange?.value ?? - vehicleStatus?.dte?.value, - // EV - range: vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.totalAvailableRange?.value, - rangeEV: vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.evModeRange?.value, - plugedTo: vehicleStatus?.evStatus?.batteryPlugin ?? EVPlugTypes.UNPLUGED, - charging: vehicleStatus?.evStatus?.batteryCharge, - estimatedCurrentChargeDuration: vehicleStatus?.evStatus?.remainTime2?.atc?.value, - estimatedFastChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc1?.value, - estimatedPortableChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc2?.value, - estimatedStationChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc3?.value, - batteryCharge12v: vehicleStatus?.battery?.batSoc, - batteryChargeHV: vehicleStatus?.evStatus?.batteryStatus, - }, - lastupdate: vehicleStatus?.time ? parseDate(vehicleStatus?.time) : null, - }; - - if (!parsedStatus.engine.range) { - if (parsedStatus.engine.rangeEV || parsedStatus.engine.rangeGas) { - parsedStatus.engine.range = - (parsedStatus.engine.rangeEV ?? 0) + (parsedStatus.engine.rangeGas ?? 0); + + public async lock(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/door`, { + body: { + action: 'close', + deviceId: this.controller.session.deviceId, + }, + }) + ); + if (response.statusCode === 200) { + logger.debug(`Vehicle ${this.vehicleConfig.id} locked`); + return 'Lock successful'; + } + return 'Something went wrong!'; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.lock'); } - } + } + + public async unlock(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/door`, { + body: { + action: 'open', + deviceId: this.controller.session.deviceId, + }, + }) + ); - this._status = statusConfig.parsed ? parsedStatus : vehicleStatus; + if (response.statusCode === 200) { + logger.debug(`Vehicle ${this.vehicleConfig.id} unlocked`); + return 'Unlock successful'; + } - return this._status; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.status'); + return 'Something went wrong!'; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.unlock'); + } } - } - - public async odometer(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status/latest`) - ); - this._odometer = response.body.resMsg.vehicleStatusInfo.odometer as VehicleOdometer; - return this._odometer; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.odometer'); + + public async fullStatus(input: VehicleStatusOptions): Promise { + const statusConfig = { + ...DEFAULT_VEHICLE_STATUS_OPTIONS, + ...input, + }; + + const http = await this.controller.getVehicleHttpService(); + + try { + const cachedResponse = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status/latest`) + ); + + const fullStatus = cachedResponse.body.resMsg.vehicleStatusInfo; + + if (statusConfig.refresh) { + const statusResponse = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status`) + ); + fullStatus.vehicleStatus = statusResponse.body.resMsg; + + const locationResponse = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location`) + ); + fullStatus.vehicleLocation = locationResponse.body.resMsg.gpsDetail; + } + + this._fullStatus = fullStatus; + return this._fullStatus; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.fullStatus'); + } } - } - - public async location(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location`) - ); - - const data = response.body.resMsg?.gpsDetail ?? response.body.resMsg; - this._location = { - latitude: data?.coord?.lat, - longitude: data?.coord?.lon, - altitude: data?.coord?.alt, - speed: { - unit: data?.speed?.unit, - value: data?.speed?.value, - }, - heading: data?.head, - }; - - return this._location; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.location'); + + public async status( + input: VehicleStatusOptions + ): Promise { + const statusConfig = { + ...DEFAULT_VEHICLE_STATUS_OPTIONS, + ...input, + }; + + const http = await this.controller.getVehicleHttpService(); + + try { + const cacheString = statusConfig.refresh ? '' : '/latest'; + + const response = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status${cacheString}`) + ); + + // handles refreshing data + const vehicleStatus = statusConfig.refresh + ? response.body.resMsg + : response.body.resMsg.vehicleStatusInfo.vehicleStatus; + + const parsedStatus: VehicleStatus = { + chassis: { + hoodOpen: vehicleStatus?.hoodOpen, + trunkOpen: vehicleStatus?.trunkOpen, + locked: vehicleStatus.doorLock, + openDoors: { + frontRight: !!vehicleStatus?.doorOpen?.frontRight, + frontLeft: !!vehicleStatus?.doorOpen?.frontLeft, + backLeft: !!vehicleStatus?.doorOpen?.backLeft, + backRight: !!vehicleStatus?.doorOpen?.backRight, + }, + tirePressureWarningLamp: { + rearLeft: !!vehicleStatus?.tirePressureLamp?.tirePressureLampRL, + frontLeft: !!vehicleStatus?.tirePressureLamp?.tirePressureLampFL, + frontRight: !!vehicleStatus?.tirePressureLamp?.tirePressureLampFR, + rearRight: !!vehicleStatus?.tirePressureLamp?.tirePressureLampRR, + all: !!vehicleStatus?.tirePressureLamp?.tirePressureWarningLampAll, + }, + }, + climate: { + active: vehicleStatus?.airCtrlOn, + steeringwheelHeat: !!vehicleStatus?.steerWheelHeat, + sideMirrorHeat: false, + rearWindowHeat: !!vehicleStatus?.sideBackWindowHeat, + defrost: vehicleStatus?.defrost, + temperatureSetpoint: tempCodeToCelsius(REGIONS.EU, vehicleStatus?.airTemp?.value), + temperatureUnit: vehicleStatus?.airTemp?.unit, + }, + engine: { + ignition: vehicleStatus.engine, + accessory: vehicleStatus?.acc, + rangeGas: + vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.gasModeRange?.value ?? + vehicleStatus?.dte?.value, + // EV + range: vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.totalAvailableRange?.value, + rangeEV: vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.evModeRange?.value, + plugedTo: vehicleStatus?.evStatus?.batteryPlugin ?? EVPlugTypes.UNPLUGED, + charging: vehicleStatus?.evStatus?.batteryCharge, + estimatedCurrentChargeDuration: vehicleStatus?.evStatus?.remainTime2?.atc?.value, + estimatedFastChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc1?.value, + estimatedPortableChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc2?.value, + estimatedStationChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc3?.value, + batteryCharge12v: vehicleStatus?.battery?.batSoc, + batteryChargeHV: vehicleStatus?.evStatus?.batteryStatus, + }, + lastupdate: vehicleStatus?.time ? parseDate(vehicleStatus?.time) : null, + }; + + if (!parsedStatus.engine.range) { + if (parsedStatus.engine.rangeEV || parsedStatus.engine.rangeGas) { + parsedStatus.engine.range = + (parsedStatus.engine.rangeEV ?? 0) + (parsedStatus.engine.rangeGas ?? 0); + } + } + + this._status = statusConfig.parsed ? parsedStatus : vehicleStatus; + + return this._status; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.status'); + } } - } - - public async startCharge(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/charge`, { - body: { - action: 'start', - deviceId: this.controller.session.deviceId, - }, - }) - ); - - if (response.statusCode === 200) { - logger.debug(`Send start charge command to Vehicle ${this.vehicleConfig.id}`); - return 'Start charge successful'; - } - - throw 'Something went wrong!'; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.startCharge'); + + public async odometer(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status/latest`) + ); + this._odometer = response.body.resMsg.vehicleStatusInfo.odometer as VehicleOdometer; + return this._odometer; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.odometer'); + } } - } - - public async stopCharge(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/charge`, { - body: { - action: 'stop', - deviceId: this.controller.session.deviceId, - }, - }) - ); - - if (response.statusCode === 200) { - logger.debug(`Send stop charge command to Vehicle ${this.vehicleConfig.id}`); - return 'Stop charge successful'; - } - - throw 'Something went wrong!'; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.stopCharge'); + + public async location(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location`) + ); + + const data = response.body.resMsg?.gpsDetail ?? response.body.resMsg; + this._location = { + latitude: data?.coord?.lat, + longitude: data?.coord?.lon, + altitude: data?.coord?.alt, + speed: { + unit: data?.speed?.unit, + value: data?.speed?.value, + }, + heading: data?.head, + }; + + return this._location; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.location'); + } } - } - public async monthlyReport( - month: { year: number; month: number } = { - year: new Date().getFullYear(), - month: new Date().getMonth() + 1, + public async startCharge(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/charge`, { + body: { + action: 'start', + deviceId: this.controller.session.deviceId, + }, + }) + ); + + if (response.statusCode === 200) { + logger.debug(`Send start charge command to Vehicle ${this.vehicleConfig.id}`); + return 'Start charge successful'; + } + + throw 'Something went wrong!'; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.startCharge'); + } } - ): Promise | undefined> { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/monthlyreport`, { - body: { - setRptMonth: toMonthDate(month), - }, - }) - ); - const rawData = response.body.resMsg?.monthlyReport; - if (rawData) { - return { - start: rawData.ifo?.mvrMonthStart, - end: rawData.ifo?.mvrMonthEnd, - breakdown: rawData.breakdown, - driving: rawData.driving - ? { - distance: rawData.driving?.runDistance, - startCount: rawData.driving?.engineStartCount, - durations: { - idle: rawData.driving?.engineIdleTime, - drive: rawData.driving?.engineOnTime, - }, - } - : undefined, - vehicleStatus: rawData.vehicleStatus - ? { - tpms: rawData.vehicleStatus?.tpmsSupport - ? Boolean(rawData.vehicleStatus?.tpmsSupport) - : undefined, - tirePressure: { - all: rawData.vehicleStatus?.tirePressure?.tirePressureLampAll == '1', - }, - } - : undefined, - }; - } - return; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.monthyReports'); + + public async stopCharge(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/charge`, { + body: { + action: 'stop', + deviceId: this.controller.session.deviceId, + }, + }) + ); + + if (response.statusCode === 200) { + logger.debug(`Send stop charge command to Vehicle ${this.vehicleConfig.id}`); + return 'Stop charge successful'; + } + + throw 'Something went wrong!'; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.stopCharge'); + } } - } - - public async tripInfo(date: { - year: number; - month: number; - day: number; - }): Promise[] | undefined>; - public async tripInfo(date?: { - year: number; - month: number; - }): Promise | undefined>; - - public async tripInfo( - date: { year: number; month: number; day?: number } = { - year: new Date().getFullYear(), - month: new Date().getMonth() + 1, + + public async monthlyReport( + month: { year: number; month: number } = { + year: new Date().getFullYear(), + month: new Date().getMonth() + 1, + } + ): Promise | undefined> { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/monthlyreport`, { + body: { + setRptMonth: toMonthDate(month), + }, + }) + ); + const rawData = response.body.resMsg?.monthlyReport; + if (rawData) { + return { + start: rawData.ifo?.mvrMonthStart, + end: rawData.ifo?.mvrMonthEnd, + breakdown: rawData.breakdown, + driving: rawData.driving + ? { + distance: rawData.driving?.runDistance, + startCount: rawData.driving?.engineStartCount, + durations: { + idle: rawData.driving?.engineIdleTime, + drive: rawData.driving?.engineOnTime, + }, + } + : undefined, + vehicleStatus: rawData.vehicleStatus + ? { + tpms: rawData.vehicleStatus?.tpmsSupport + ? Boolean(rawData.vehicleStatus?.tpmsSupport) + : undefined, + tirePressure: { + all: rawData.vehicleStatus?.tirePressure?.tirePressureLampAll == '1', + }, + } + : undefined, + }; + } + return; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.monthyReports'); + } } - ): Promise[] | DeepPartial | undefined> { - const http = await this.controller.getApiHttpService(); - try { - const perDay = Boolean(date.day); - const response = this.updateRates( - await http.post(`/api/v1/spa/vehicles/${this.vehicleConfig.id}/tripinfo`, { - body: { - setTripLatest: 10, - setTripMonth: !perDay ? toMonthDate(date) : undefined, - setTripDay: perDay ? toDayDate(date) : undefined, - tripPeriodType: perDay ? 1 : 0, - }, - }) - ); - - if (!perDay) { - const rawData = response.body.resMsg; - return { - days: Array.isArray(rawData?.tripDayList) - ? rawData?.tripDayList.map(day => ({ - dayRaw: day.tripDayInMonth, - date: day.tripDayInMonth ? parseDate(day.tripDayInMonth) : undefined, - tripsCount: day.tripCntDay, - })) - : [], - durations: { - drive: rawData?.tripDrvTime, - idle: rawData?.tripIdleTime, - }, - distance: rawData?.tripDist, - speed: { - avg: rawData?.tripAvgSpeed, - max: rawData?.tripMaxSpeed, - }, - } as VehicleMonthTrip; - } else { - const rawData = response.body.resMsg.dayTripList; - if (rawData && Array.isArray(rawData)) { - return rawData.map(day => ({ - dayRaw: day.tripDay, - tripsCount: day.dayTripCnt, - distance: day.tripDist, - durations: { - drive: day.tripDrvTime, - idle: day.tripIdleTime, - }, - speed: { - avg: day.tripAvgSpeed, - max: day.tripMaxSpeed, - }, - trips: Array.isArray(day.tripList) - ? day.tripList.map(trip => { - const start = parseDate(`${day.tripDay}${trip.tripTime}`); - return { - timeRaw: trip.tripTime, - start, - end: addMinutes(start, trip.tripDrvTime), + + public async tripInfo(date: { + year: number; + month: number; + day: number; + }): Promise[] | undefined>; + public async tripInfo(date?: { + year: number; + month: number; + }): Promise | undefined>; + + public async tripInfo( + date: { year: number; month: number; day?: number } = { + year: new Date().getFullYear(), + month: new Date().getMonth() + 1, + } + ): Promise[] | DeepPartial | undefined> { + const http = await this.controller.getApiHttpService(); + try { + const perDay = Boolean(date.day); + const response = this.updateRates( + await http.post(`/api/v1/spa/vehicles/${this.vehicleConfig.id}/tripinfo`, { + body: { + setTripLatest: 10, + setTripMonth: !perDay ? toMonthDate(date) : undefined, + setTripDay: perDay ? toDayDate(date) : undefined, + tripPeriodType: perDay ? 1 : 0, + }, + }) + ); + + if (!perDay) { + const rawData = response.body.resMsg; + return { + days: Array.isArray(rawData?.tripDayList) + ? rawData?.tripDayList.map(day => ({ + dayRaw: day.tripDayInMonth, + date: day.tripDayInMonth ? parseDate(day.tripDayInMonth) : undefined, + tripsCount: day.tripCntDay, + })) + : [], durations: { - drive: trip.tripDrvTime, - idle: trip.tripIdleTime, + drive: rawData?.tripDrvTime, + idle: rawData?.tripIdleTime, }, + distance: rawData?.tripDist, speed: { - avg: trip.tripAvgSpeed, - max: trip.tripMaxSpeed, + avg: rawData?.tripAvgSpeed, + max: rawData?.tripMaxSpeed, }, - distance: trip.tripDist, - }; - }) - : [], - })); + } as VehicleMonthTrip; + } else { + const rawData = response.body.resMsg.dayTripList; + if (rawData && Array.isArray(rawData)) { + return rawData.map(day => ({ + dayRaw: day.tripDay, + tripsCount: day.dayTripCnt, + distance: day.tripDist, + durations: { + drive: day.tripDrvTime, + idle: day.tripIdleTime, + }, + speed: { + avg: day.tripAvgSpeed, + max: day.tripMaxSpeed, + }, + trips: Array.isArray(day.tripList) + ? day.tripList.map(trip => { + const start = parseDate(`${day.tripDay}${trip.tripTime}`); + return { + timeRaw: trip.tripTime, + start, + end: addMinutes(start, trip.tripDrvTime), + durations: { + drive: trip.tripDrvTime, + idle: trip.tripIdleTime, + }, + speed: { + avg: trip.tripAvgSpeed, + max: trip.tripMaxSpeed, + }, + distance: trip.tripDist, + }; + }) + : [], + })); + } + } + return; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.history'); + } + } + + public async driveHistory(period: historyDrivingPeriod = historyDrivingPeriod.DAY): Promise< + DeepPartial<{ + cumulated: EUDriveHistory[]; + history: EUDatedDriveHistory[]; + }> + > { + const http = await this.controller.getApiHttpService(); + try { + const response = await http.post(`/api/v1/spa/vehicles/${this.vehicleConfig.id}/drvhistory`, { + body: { + periodTarget: period, + }, + }); + return { + cumulated: response.body.resMsg.drivingInfo.map(line => ({ + period: line.drivingPeriod, + consumption: { + total: line.totalPwrCsp, + engine: line.motorPwrCsp, + climate: line.climatePwrCsp, + devices: line.eDPwrCsp, + battery: line.batteryMgPwrCsp, + }, + regen: line.regenPwr, + distance: line.calculativeOdo, + })), + history: response.body.resMsg.drivingInfoDetail.map(line => ({ + period: line.drivingPeriod, + rawDate: line.drivingDate, + date: line.drivingDate ? parseDate(line.drivingDate) : undefined, + consumption: { + total: line.totalPwrCsp, + engine: line.motorPwrCsp, + climate: line.climatePwrCsp, + devices: line.eDPwrCsp, + battery: line.batteryMgPwrCsp, + }, + regen: line.regenPwr, + distance: line.calculativeOdo, + })), + }; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.history'); } - } - return; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.history'); } - } - - public async driveHistory(period: historyDrivingPeriod = historyDrivingPeriod.DAY): Promise< - DeepPartial<{ - cumulated: EUDriveHistory[]; - history: EUDatedDriveHistory[]; - }> - > { - const http = await this.controller.getApiHttpService(); - try { - const response = await http.post(`/api/v1/spa/vehicles/${this.vehicleConfig.id}/drvhistory`, { - body: { - periodTarget: period, - }, - }); - return { - cumulated: response.body.resMsg.drivingInfo.map(line => ({ - period: line.drivingPeriod, - consumption: { - total: line.totalPwrCsp, - engine: line.motorPwrCsp, - climate: line.climatePwrCsp, - devices: line.eDPwrCsp, - battery: line.batteryMgPwrCsp, - }, - regen: line.regenPwr, - distance: line.calculativeOdo, - })), - history: response.body.resMsg.drivingInfoDetail.map(line => ({ - period: line.drivingPeriod, - rawDate: line.drivingDate, - date: line.drivingDate ? parseDate(line.drivingDate) : undefined, - consumption: { - total: line.totalPwrCsp, - engine: line.motorPwrCsp, - climate: line.climatePwrCsp, - devices: line.eDPwrCsp, - battery: line.batteryMgPwrCsp, - }, - regen: line.regenPwr, - distance: line.calculativeOdo, - })), - }; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.history'); + + /** + * Warning: Only works on EV + */ + public async getChargeTargets(): Promise[] | undefined> { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/charge/target`) + ); + const rawData = response.body.resMsg?.targetSOClist; + if (rawData && Array.isArray(rawData)) { + return rawData.map(rawSOC => ({ + distance: rawSOC.drvDistance?.distanceType?.distanceValue, + targetLevel: rawSOC.targetSOClevel, + type: rawSOC.plugType, + })); + } + return; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.getChargeTargets'); + } } - } - - /** - * Warning: Only works on EV - */ - public async getChargeTargets(): Promise[] | undefined> { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/charge/target`) - ); - const rawData = response.body.resMsg?.targetSOClist; - if (rawData && Array.isArray(rawData)) { - return rawData.map(rawSOC => ({ - distance: rawSOC.drvDistance?.distanceType?.distanceValue, - targetLevel: rawSOC.targetSOClevel, - type: rawSOC.plugType, - })); - } - return; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.getChargeTargets'); + + /** + * Warning: Only works on EV + */ + public async setChargeTargets(limits: { fast: ChargeTarget; slow: ChargeTarget }): Promise { + const http = await this.controller.getVehicleHttpService(); + 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(', ')}` + ); + } + try { + this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/charge/target`, { + body: { + targetSOClist: [ + { plugType: EVChargeModeTypes.FAST, targetSOClevel: limits.fast }, + { plugType: EVChargeModeTypes.SLOW, targetSOClevel: limits.slow }, + ], + }, + }) + ); + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.setChargeTargets'); + } } - } - - /** - * Warning: Only works on EV - */ - public async setChargeTargets(limits: { fast: ChargeTarget; slow: ChargeTarget }): Promise { - const http = await this.controller.getVehicleHttpService(); - 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(', ')}` - ); + + /** + * Define a navigation route + * @param poiInformations The list of POIs and waypoint to go through + */ + public async setNavigation(poiInformations: EUPOIInformation[]): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location/routes`, { + body: { + deviceID: this.controller.session.deviceId, + poiInfoList: poiInformations, + }, + }) + ); + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.setNavigation'); + } } - try { - this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/charge/target`, { - body: { - targetSOClist: [ - { plugType: EVChargeModeTypes.FAST, targetSOClevel: limits.fast }, - { plugType: EVChargeModeTypes.SLOW, targetSOClevel: limits.slow }, - ], - }, - }) - ); - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.setChargeTargets'); + + + public async getChargeSchedule(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates(await http.get( + `/api/v2/spa/vehicles/${this.vehicleConfig.id}/reservation/charge`)); + const result = response.body.resMsg as ReservationCharge; + return result; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.getChargeSchedule'); + } } - } - - /** - * Define a navigation route - * @param poiInformations The list of POIs and waypoint to go through - */ - public async setNavigation(poiInformations: EUPOIInformation[]): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location/routes`, { - body: { - deviceID: this.controller.session.deviceId, - poiInfoList: poiInformations, - }, - }) - ); - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.setNavigation'); + + /** Warning: doesn't work yet. + * Returns a 503 error when called, + * even when Android app works fine */ + public async setChargeSchedule(schedule: ReservationCharge): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates(await http.post( + `/api/v2/spa/vehicles/${this.vehicleConfig.id}/reservation/charge`, { + body: schedule + }) + ); + return response; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.setChargeSchedule'); + + } } - } - - private updateRates>(resp: got.Response): got.Response { - if (resp.headers?.['x-ratelimit-limit']) { - this.serverRates.max = Number(resp.headers?.['x-ratelimit-limit']); - this.serverRates.current = Number(resp.headers?.['x-ratelimit-remaining']); - if (resp.headers?.['x-ratelimit-reset']) { - this.serverRates.reset = new Date(Number(`${resp.headers?.['x-ratelimit-reset']}000`)); - } - this.serverRates.updatedAt = new Date(); + + private updateRates>(resp: got.Response): got.Response { + if (resp.headers?.['x-ratelimit-limit']) { + this.serverRates.max = Number(resp.headers?.['x-ratelimit-limit']); + this.serverRates.current = Number(resp.headers?.['x-ratelimit-remaining']); + if (resp.headers?.['x-ratelimit-reset']) { + this.serverRates.reset = new Date(Number(`${resp.headers?.['x-ratelimit-reset']}000`)); + } + this.serverRates.updatedAt = new Date(); + } + return resp; } - return resp; - } } function toMonthDate(month: { year: number; month: number }) { - return `${month.year}${month.month.toString().padStart(2, '0')}`; + return `${month.year}${month.month.toString().padStart(2, '0')}`; } function toDayDate(date: { year: number; month: number; day?: number }) { - return date.day - ? `${toMonthDate(date)}${date.day.toString().padStart(2, '0')}` - : toMonthDate(date); + return date.day + ? `${toMonthDate(date)}${date.day.toString().padStart(2, '0')}` + : toMonthDate(date); } From 85bfa2ea3aa9edc564df06fe6f40d46540c046ab Mon Sep 17 00:00:00 2001 From: Kasper Guldmann Nielsen Date: Sun, 2 Oct 2022 01:19:10 +0200 Subject: [PATCH 2/2] Undo reformatting --- src/interfaces/common.interfaces.ts | 950 ++++++++++----------- src/vehicles/european.vehicle.ts | 1228 +++++++++++++-------------- 2 files changed, 1089 insertions(+), 1089 deletions(-) diff --git a/src/interfaces/common.interfaces.ts b/src/interfaces/common.interfaces.ts index 4a11ef4..709ed10 100644 --- a/src/interfaces/common.interfaces.ts +++ b/src/interfaces/common.interfaces.ts @@ -4,594 +4,594 @@ export type Brand = 'kia' | 'hyundai'; // config export interface BlueLinkyConfig { - username: string | undefined; - password: string | undefined; - region: REGION | undefined; - brand: Brand; - autoLogin?: boolean; - pin: string | undefined; - vin?: string | undefined; - vehicleId?: string | undefined; + username: string | undefined; + password: string | undefined; + region: REGION | undefined; + brand: Brand; + autoLogin?: boolean; + pin: string | undefined; + vin?: string | undefined; + vehicleId?: string | undefined; } export interface BluelinkVehicle { - name: string; - vin: string; - type: string; + name: string; + vin: string; + type: string; } export interface Session { - accessToken?: string; - refreshToken?: string; - controlToken?: string; - deviceId?: string; - tokenExpiresAt: number; - controlTokenExpiresAt?: number; + accessToken?: string; + refreshToken?: string; + controlToken?: string; + deviceId?: string; + tokenExpiresAt: number; + controlTokenExpiresAt?: number; } export enum EVPlugTypes { - UNPLUGED = 0, - FAST = 1, - PORTABLE = 2, - STATION = 3 + UNPLUGED = 0, + FAST = 1, + PORTABLE = 2, + STATION = 3 } export enum EVChargeModeTypes { - FAST = 0, - SLOW = 1, + FAST = 0, + SLOW = 1, } // Status remapped export interface VehicleStatus { - engine: { - ignition: boolean; - batteryCharge?: number; - charging?: boolean; - timeToFullCharge?: unknown; - range: number; - rangeGas?: number; - rangeEV?: number; - plugedTo?: EVPlugTypes; - estimatedCurrentChargeDuration?: number; - estimatedFastChargeDuration?: number; - estimatedPortableChargeDuration?: number; - estimatedStationChargeDuration?: number; - batteryCharge12v?: number; - batteryChargeHV?: number; - accessory: boolean; - }; - climate: { - active: boolean; - steeringwheelHeat: boolean; - sideMirrorHeat: boolean; - rearWindowHeat: boolean; - temperatureSetpoint: number; - temperatureUnit: number; - defrost: boolean; + engine: { + ignition: boolean; + batteryCharge?: number; + charging?: boolean; + timeToFullCharge?: unknown; + range: number; + rangeGas?: number; + rangeEV?: number; + plugedTo?: EVPlugTypes; + estimatedCurrentChargeDuration?: number; + estimatedFastChargeDuration?: number; + estimatedPortableChargeDuration?: number; + estimatedStationChargeDuration?: number; + batteryCharge12v?: number; + batteryChargeHV?: number; + accessory: boolean; + }; + climate: { + active: boolean; + steeringwheelHeat: boolean; + sideMirrorHeat: boolean; + rearWindowHeat: boolean; + temperatureSetpoint: number; + temperatureUnit: number; + defrost: boolean; + }; + chassis: { + hoodOpen: boolean; + trunkOpen: boolean; + locked: boolean; + openDoors: { + frontRight: boolean; + frontLeft: boolean; + backLeft: boolean; + backRight: boolean; }; - chassis: { - hoodOpen: boolean; - trunkOpen: boolean; - locked: boolean; - openDoors: { - frontRight: boolean; - frontLeft: boolean; - backLeft: boolean; - backRight: boolean; - }; - tirePressureWarningLamp: { - rearLeft: boolean; - frontLeft: boolean; - frontRight: boolean; - rearRight: boolean; - all: boolean; - }; + tirePressureWarningLamp: { + rearLeft: boolean; + frontLeft: boolean; + frontRight: boolean; + rearRight: boolean; + all: boolean; }; - lastupdate: Date | null + }; + lastupdate: Date | null } // TODO: fix/update export interface FullVehicleStatus { - vehicleLocation: { - coord: { lat: number; lon: number; alt: number; type: number }; - head: number; - speed: { value: number; unit: number }; - accuracy: { hdop: number; pdop: number }; - time: string; - }; - odometer: { value: number, unit: number }; - vehicleStatus: { - time: string; - airCtrlOn: boolean; - engine: boolean; - doorLock: boolean; - doorOpen: { frontRight: number; frontLeft: number; backLeft: number; backRight: number }; - trunkOpen: boolean; - airTemp: { unit: number; hvacTempType: number; value: string }; - defrost: boolean; - acc: boolean; - ign3: boolean; - hoodOpen: boolean; - transCond: boolean; - steerWheelHeat: number; - sideBackWindowHeat: number; - tirePressureLamp: { - tirePressureWarningLampAll: number; - tirePressureWarningLampFL: number; - tirePressureWarningLampFR: number; - tirePressureWarningLampRL: number; - tirePressureWarningLampRR: number; - }; - battery: { batSoc: number; batState: number; }; - evStatus: { - batteryCharge: boolean; - batteryStatus: number; - batteryPlugin: number; - remainTime2: { - etc1: { value: number; unit: number; }; - etc2: { value: number; unit: number; }; - etc3: { value: number; unit: number; }; - atc: { value: number; unit: number; }; - }; - drvDistance: [ - { - rangeByFuel: { - gasModeRange: { value: number; unit: number }; - evModeRange: { value: number; unit: number }; - totalAvailableRange: { value: number; unit: number }; - }; - type: number; - } - ]; - // "reservChargeInfos": { - // "reservChargeInfo": { - // "reservChargeInfoDetail": { - // "reservInfo": { - // "day": [ - // 1, - // 2, - // 3, - // 4, - // 5 - // ], - // "time": { - // "time": "0800", - // "timeSection": 0 - // } - // }, - // "reservChargeSet": true, - // "reservFatcSet": { - // "defrost": false, - // "airTemp": { - // "value": "00H", - // "unit": 0, - // "hvacTempType": 1 - // }, - // "airCtrl": 0, - // "heating1": 0 - // } - // } - // }, - // "offpeakPowerInfo": { - // "offPeakPowerTime1": { - // "starttime": { - // "time": "1200", - // "timeSection": 0 - // }, - // "endtime": { - // "time": "1200", - // "timeSection": 0 - // } - // }, - // "offPeakPowerFlag": 1 - // }, - // "reserveChargeInfo2": { - // "reservChargeInfoDetail": { - // "reservInfo": { - // "day": [ - // 9 - // ], - // "time": { - // "time": "1200", - // "timeSection": 0 - // } - // }, - // "reservChargeSet": false, - // "reservFatcSet": { - // "defrost": false, - // "airTemp": { - // "value": "00H", - // "unit": 0, - // "hvacTempType": 1 - // }, - // "airCtrl": 0, - // "heating1": 0 - // } - // } - // }, - // "reservFlag": 0, - // "ect": { - // "start": { - // "day": 9, - // "time": { - // "time": "1200", - // "timeSection": 0 - // } - // }, - // "end": { - // "day": 9, - // "time": { - // "time": "1200", - // "timeSection": 0 - // } - // } - // }, - // "targetSOClist": [ - // { - // "targetSOClevel": 90, - // "dte": { - // "rangeByFuel": { - // "evModeRange": { - // "value": 392, - // "unit": 1 - // }, - // "totalAvailableRange": { - // "value": 392, - // "unit": 1 - // } - // }, - // "type": 2 - // }, - // "plugType": 0 - // }, - // { - // "targetSOClevel": 80, - // "dte": { - // "rangeByFuel": { - // "evModeRange": { - // "value": 345, - // "unit": 1 - // }, - // "totalAvailableRange": { - // "value": 345, - // "unit": 1 - // } - // }, - // "type": 2 - // }, - // "plugType": 1 - // } - // ] - // } - }; - } -} - -// TODO: remove -// ======= -// Rough mapping of the raw status that might no be the same for all regions - -export interface RawVehicleStatus { - lastStatusDate: string; - dateTime: string; - acc: boolean; - trunkOpen: boolean; + vehicleLocation: { + coord: { lat: number; lon: number; alt: number; type: number }; + head: number; + speed: { value: number; unit: number }; + accuracy: { hdop: number; pdop: number }; + time: string; + }; + odometer: { value: number, unit: number }; + vehicleStatus: { + time: string; + airCtrlOn: boolean; + engine: boolean; doorLock: boolean; - defrostStatus: string; - transCond: boolean; - doorLockStatus: string; doorOpen: { frontRight: number; frontLeft: number; backLeft: number; backRight: number }; - airCtrlOn: boolean; - airTempUnit: string; + trunkOpen: boolean; airTemp: { unit: number; hvacTempType: number; value: string }; - battery: { - batSignalReferenceValue: unknown; - batSoc: number; - batState: number; - sjbDeliveryMode: number; - }; - ign3: boolean; - ignitionStatus: string; - lowFuelLight: boolean; - sideBackWindowHeat: number; - dte: { unit: number; value: number }; - engine: boolean; defrost: boolean; + acc: boolean; + ign3: boolean; hoodOpen: boolean; - airConditionStatus: string; + transCond: boolean; steerWheelHeat: number; + sideBackWindowHeat: number; tirePressureLamp: { - tirePressureWarningLampRearLeft: number; - tirePressureWarningLampFrontLeft: number; - tirePressureWarningLampFrontRight: number; - tirePressureWarningLampAll: number; - tirePressureWarningLampRearRight: number; + tirePressureWarningLampAll: number; + tirePressureWarningLampFL: number; + tirePressureWarningLampFR: number; + tirePressureWarningLampRL: number; + tirePressureWarningLampRR: number; }; - trunkOpenStatus: string; + battery: { batSoc: number; batState: number; }; evStatus: { - batteryCharge: boolean; - batteryStatus: number; - batteryPlugin: number; - remainTime2: { - etc1: { value: number; unit: number }; - etc2: { value: number; unit: number }; - etc3: { value: number; unit: number }; - atc: { value: number; unit: number }; - }; - drvDistance: [ - { - rangeByFuel: { - gasModeRange: { value: number; unit: number }; - evModeRange: { value: number; unit: number }; - totalAvailableRange: { value: number; unit: number }; - }; - type: number; - } - ]; + batteryCharge: boolean; + batteryStatus: number; + batteryPlugin: number; + remainTime2: { + etc1: { value: number; unit: number; }; + etc2: { value: number; unit: number; }; + etc3: { value: number; unit: number; }; + atc: { value: number; unit: number; }; + }; + drvDistance: [ + { + rangeByFuel: { + gasModeRange: { value: number; unit: number }; + evModeRange: { value: number; unit: number }; + totalAvailableRange: { value: number; unit: number }; + }; + type: number; + } + ]; + // "reservChargeInfos": { + // "reservChargeInfo": { + // "reservChargeInfoDetail": { + // "reservInfo": { + // "day": [ + // 1, + // 2, + // 3, + // 4, + // 5 + // ], + // "time": { + // "time": "0800", + // "timeSection": 0 + // } + // }, + // "reservChargeSet": true, + // "reservFatcSet": { + // "defrost": false, + // "airTemp": { + // "value": "00H", + // "unit": 0, + // "hvacTempType": 1 + // }, + // "airCtrl": 0, + // "heating1": 0 + // } + // } + // }, + // "offpeakPowerInfo": { + // "offPeakPowerTime1": { + // "starttime": { + // "time": "1200", + // "timeSection": 0 + // }, + // "endtime": { + // "time": "1200", + // "timeSection": 0 + // } + // }, + // "offPeakPowerFlag": 1 + // }, + // "reserveChargeInfo2": { + // "reservChargeInfoDetail": { + // "reservInfo": { + // "day": [ + // 9 + // ], + // "time": { + // "time": "1200", + // "timeSection": 0 + // } + // }, + // "reservChargeSet": false, + // "reservFatcSet": { + // "defrost": false, + // "airTemp": { + // "value": "00H", + // "unit": 0, + // "hvacTempType": 1 + // }, + // "airCtrl": 0, + // "heating1": 0 + // } + // } + // }, + // "reservFlag": 0, + // "ect": { + // "start": { + // "day": 9, + // "time": { + // "time": "1200", + // "timeSection": 0 + // } + // }, + // "end": { + // "day": 9, + // "time": { + // "time": "1200", + // "timeSection": 0 + // } + // } + // }, + // "targetSOClist": [ + // { + // "targetSOClevel": 90, + // "dte": { + // "rangeByFuel": { + // "evModeRange": { + // "value": 392, + // "unit": 1 + // }, + // "totalAvailableRange": { + // "value": 392, + // "unit": 1 + // } + // }, + // "type": 2 + // }, + // "plugType": 0 + // }, + // { + // "targetSOClevel": 80, + // "dte": { + // "rangeByFuel": { + // "evModeRange": { + // "value": 345, + // "unit": 1 + // }, + // "totalAvailableRange": { + // "value": 345, + // "unit": 1 + // } + // }, + // "type": 2 + // }, + // "plugType": 1 + // } + // ] + // } }; - remoteIgnition: boolean; - seatHeaterVentInfo: unknown; - sleepModeCheck: boolean; - lampWireStatus: { - headLamp: unknown; - stopLamp: unknown; - turnSignalLamp: unknown; + } +} + +// TODO: remove +// ======= +// Rough mapping of the raw status that might no be the same for all regions + +export interface RawVehicleStatus { + lastStatusDate: string; + dateTime: string; + acc: boolean; + trunkOpen: boolean; + doorLock: boolean; + defrostStatus: string; + transCond: boolean; + doorLockStatus: string; + doorOpen: { frontRight: number; frontLeft: number; backLeft: number; backRight: number }; + airCtrlOn: boolean; + airTempUnit: string; + airTemp: { unit: number; hvacTempType: number; value: string }; + battery: { + batSignalReferenceValue: unknown; + batSoc: number; + batState: number; + sjbDeliveryMode: number; + }; + ign3: boolean; + ignitionStatus: string; + lowFuelLight: boolean; + sideBackWindowHeat: number; + dte: { unit: number; value: number }; + engine: boolean; + defrost: boolean; + hoodOpen: boolean; + airConditionStatus: string; + steerWheelHeat: number; + tirePressureLamp: { + tirePressureWarningLampRearLeft: number; + tirePressureWarningLampFrontLeft: number; + tirePressureWarningLampFrontRight: number; + tirePressureWarningLampAll: number; + tirePressureWarningLampRearRight: number; + }; + trunkOpenStatus: string; + evStatus: { + batteryCharge: boolean; + batteryStatus: number; + batteryPlugin: number; + remainTime2: { + etc1: { value: number; unit: number }; + etc2: { value: number; unit: number }; + etc3: { value: number; unit: number }; + atc: { value: number; unit: number }; }; - windowOpen: unknown; - engineRuntime: unknown; + drvDistance: [ + { + rangeByFuel: { + gasModeRange: { value: number; unit: number }; + evModeRange: { value: number; unit: number }; + totalAvailableRange: { value: number; unit: number }; + }; + type: number; + } + ]; + }; + remoteIgnition: boolean; + seatHeaterVentInfo: unknown; + sleepModeCheck: boolean; + lampWireStatus: { + headLamp: unknown; + stopLamp: unknown; + turnSignalLamp: unknown; + }; + windowOpen: unknown; + engineRuntime: unknown; } // Vehicle Info export interface VehicleInfo { - vehicleId: string; - nickName: string; - modelCode: string; - modelName: string; - modelYear: string; - fuelKindCode: string; - trim: string; - engine: string; - exteriorColor: string; - dtcCount: number; - subscriptionStatus: string; - subscriptionEndDate: string; - overviewMessage: string; - odometer: number; - odometerUnit: number; - defaultVehicle: boolean; - enrollmentStatus: string; - genType: string; - transmissionType: string; - vin: string; + vehicleId: string; + nickName: string; + modelCode: string; + modelName: string; + modelYear: string; + fuelKindCode: string; + trim: string; + engine: string; + exteriorColor: string; + dtcCount: number; + subscriptionStatus: string; + subscriptionEndDate: string; + overviewMessage: string; + odometer: number; + odometerUnit: number; + defaultVehicle: boolean; + enrollmentStatus: string; + genType: string; + transmissionType: string; + vin: string; } export interface VehicleFeatureEntry { - category: string; - features: [ + category: string; + features: [ + { + featureName: string; + features: [ { - featureName: string; - features: [ - { - subFeatureName: string; - subFeatureValue: string; - } - ]; + subFeatureName: string; + subFeatureValue: string; } - ]; + ]; + } + ]; } // Location export interface VehicleLocation { - latitude: number; - longitude: number; - altitude: number; - speed: { - unit: number; - value: number; - }; - heading: number; -} -export interface VehicleOdometer { + latitude: number; + longitude: number; + altitude: number; + speed: { unit: number; value: number; + }; + heading: number; +} +export interface VehicleOdometer { + unit: number; + value: number; } export interface VehicleStatusOptions { - refresh: boolean; - parsed: boolean; + refresh: boolean; + parsed: boolean; } // VEHICLE COMMANDS ///////////////////////////////////////////// export interface VehicleCommandResponse { - responseCode: number; // 0 is success - responseDesc: string; + responseCode: number; // 0 is success + responseDesc: string; } export interface VehicleStartOptions { - airCtrl?: boolean | string; - igniOnDuration: number; - airTempvalue?: number; - defrost?: boolean | string; - heating1?: boolean | string; + airCtrl?: boolean | string; + igniOnDuration: number; + airTempvalue?: number; + defrost?: boolean | string; + heating1?: boolean | string; } export interface VehicleClimateOptions { - defrost: boolean; - windscreenHeating: boolean; - temperature: number; - unit: string; + defrost: boolean; + windscreenHeating: boolean; + temperature: number; + unit: string; } export interface VehicleRegisterOptions { - nickname: string; - name: string; - vin: string; - regDate: string; - brandIndicator: string; - regId: string; - id: string; - generation: string; + nickname: string; + name: string; + vin: string; + regDate: string; + brandIndicator: string; + regId: string; + id: string; + generation: string; } export type DeepPartial = { - [P in keyof T]?: DeepPartial; + [P in keyof T]?: DeepPartial; }; export interface VehicleMonthlyReport { - start: string; // format YYYYMMDD, eg: 20210210 - end: string; // format YYYYMMDD, eg: 20210312 - driving: { - distance: number; - startCount: number; - durations: { - drive: number; - idle: number; - } - }, - breakdown: { - ecuIdx: string; - ecuStatus: string; - }[], - vehicleStatus: { - tpms: boolean; - tirePressure: { - all: boolean; - } + start: string; // format YYYYMMDD, eg: 20210210 + end: string; // format YYYYMMDD, eg: 20210312 + driving: { + distance: number; + startCount: number; + durations: { + drive: number; + idle: number; + } + }, + breakdown: { + ecuIdx: string; + ecuStatus: string; + }[], + vehicleStatus: { + tpms: boolean; + tirePressure: { + all: boolean; } + } } export interface VehicleTargetSOC { - type: EVChargeModeTypes; - distance: number; - targetLevel: number; + type: EVChargeModeTypes; + distance: number; + targetLevel: number; } export interface VehicleMonthTrip { - days: Array<{ dayRaw: string; date?: Date; tripsCount: number }>; - durations: { - drive: number; - idle: number; - }; - speed: { - avg: number; - max: number; - }; - distance: number; + days: Array<{ dayRaw: string; date?: Date; tripsCount: number }>; + durations: { + drive: number; + idle: number; + }; + speed: { + avg: number; + max: number; + }; + distance: number; } export interface VehicleDayTrip { - dayRaw: string; - tripsCount: number; - distance: number; + dayRaw: string; + tripsCount: number; + distance: number; + durations: { + drive: number; + idle: number; + }; + speed: { + avg: number; + max: number; + }; + trips: { + timeRaw: string; + start: Date; + end: Date; durations: { - drive: number; - idle: number; + drive: number; + idle: number; }; speed: { - avg: number; - max: number; + avg: number; + max: number; }; - trips: { - timeRaw: string; - start: Date; - end: Date; - durations: { - drive: number; - idle: number; - }; - speed: { - avg: number; - max: number; - }; - distance: number; - }[]; + distance: number; + }[]; } export const enum OffPeakPowerFlag { - OffPeakPreferred = 1, - OffPeakOnly = 2, + OffPeakPreferred = 1, + OffPeakOnly = 2, } export const enum RangeUnit { - Kilometers = 1, - //TODO determine enum value for miles + Kilometers = 1, + //TODO determine enum value for miles } export interface Range { - value: number, - unit: RangeUnit, + value: number, + unit: RangeUnit, } export interface SocTarget { - targetSOClevel: ChargeTarget, - plugType: EVChargeModeTypes, - dte?: { - rangeByFuel: { - evModeRange: Range, - totalAvailableRange: Range - } - type: number //TODO determine the meaning of this + targetSOClevel: ChargeTarget, + plugType: EVChargeModeTypes, + dte?: { + rangeByFuel: { + evModeRange: Range, + totalAvailableRange: Range } + type: number //TODO determine the meaning of this + } } export const enum Weekday { - Monday = 1, - Tyesday = 2, - Wednesday = 3, - Thursday = 4, - Friday = 5, - Saturday = 6, - Sunday = 0, - - Unknown = 9 + Monday = 1, + Tyesday = 2, + Wednesday = 3, + Thursday = 4, + Friday = 5, + Saturday = 6, + Sunday = 0, + + Unknown = 9 } /** AM or PM */ export const enum TimeSection { - AM = 0, - PM = 1 + AM = 0, + PM = 1 } /** A time of day, in the vehicle's time zone. */ export interface Time { - /** String of 4 digits, '1200' through '1259' and '0100' through '1159' */ - time: string, - timeSection: TimeSection + /** String of 4 digits, '1200' through '1259' and '0100' through '1159' */ + time: string, + timeSection: TimeSection } export interface ReservChargeInfoDetail { - reservInfo: { - day: Weekday[], - time: Time, - } - reservChargeSet: boolean, - reservFatcSet: { - defrost: boolean, - airTemp: { //TODO decode the deeper meaning of this. - value: string, - unit: number, - hvacTempType: number - }, - airCtrl: number, - heating1: number + reservInfo: { + day: Weekday[], + time: Time, + } + reservChargeSet: boolean, + reservFatcSet: { + defrost: boolean, + airTemp: { //TODO decode the deeper meaning of this. + value: string, + unit: number, + hvacTempType: number + }, + airCtrl: number, + heating1: number - } + } } export interface ReservationCharge { - reservChargeInfo: { reservChargeInfoDetail: ReservChargeInfoDetail }, - reserveChargeInfo2: { reservChargeInfoDetail: ReservChargeInfoDetail }, - offpeakPowerInfo: { - offPeakPowerTime1: { - starttime: Time, - endtime: Time - }, - offPeakPowerFlag: OffPeakPowerFlag + reservChargeInfo: { reservChargeInfoDetail: ReservChargeInfoDetail }, + reserveChargeInfo2: { reservChargeInfoDetail: ReservChargeInfoDetail }, + offpeakPowerInfo: { + offPeakPowerTime1: { + starttime: Time, + endtime: Time }, - reservFlag: number, //TODO determine the meaning of this - ect: { - start: { day: Weekday, time: Time }, - end: { day: Weekday, time: Time } - }, - targetSOClist: SocTarget[] -} \ No newline at end of file + offPeakPowerFlag: OffPeakPowerFlag + }, + reservFlag: number, //TODO determine the meaning of this + ect: { + start: { day: Weekday, time: Time }, + end: { day: Weekday, time: Time } + }, + targetSOClist: SocTarget[] +} diff --git a/src/vehicles/european.vehicle.ts b/src/vehicles/european.vehicle.ts index 98fe14c..aa3f691 100644 --- a/src/vehicles/european.vehicle.ts +++ b/src/vehicles/european.vehicle.ts @@ -1,26 +1,26 @@ import { - REGIONS, - DEFAULT_VEHICLE_STATUS_OPTIONS, - POSSIBLE_CHARGE_LIMIT_VALUES, - ChargeTarget, + REGIONS, + DEFAULT_VEHICLE_STATUS_OPTIONS, + POSSIBLE_CHARGE_LIMIT_VALUES, + ChargeTarget, } from '../constants'; import { - VehicleStatus, - FullVehicleStatus, - VehicleOdometer, - VehicleLocation, - VehicleClimateOptions, - VehicleRegisterOptions, - VehicleStatusOptions, - RawVehicleStatus, - EVPlugTypes, - VehicleMonthlyReport, - DeepPartial, - VehicleTargetSOC, - EVChargeModeTypes, - VehicleDayTrip, - VehicleMonthTrip, - ReservationCharge, + VehicleStatus, + FullVehicleStatus, + VehicleOdometer, + VehicleLocation, + VehicleClimateOptions, + VehicleRegisterOptions, + VehicleStatusOptions, + RawVehicleStatus, + EVPlugTypes, + VehicleMonthlyReport, + DeepPartial, + VehicleTargetSOC, + EVChargeModeTypes, + VehicleDayTrip, + VehicleMonthTrip, + ReservationCharge, } from '../interfaces/common.interfaces'; import logger from '../logger'; @@ -29,636 +29,636 @@ import { EuropeanController } from '../controllers/european.controller'; import { celciusToTempCode, tempCodeToCelsius, parseDate, addMinutes } from '../util'; import { manageBluelinkyError, ManagedBluelinkyError } from '../tools/common.tools'; import { - EUDatedDriveHistory, - EUDriveHistory, - EUPOIInformation, - historyDrivingPeriod, + EUDatedDriveHistory, + EUDriveHistory, + EUPOIInformation, + historyDrivingPeriod, } from '../interfaces/european.interfaces'; import got from 'got'; export default class EuropeanVehicle extends Vehicle { - public region = REGIONS.EU; - public serverRates: { - max: number; - current: number; - reset?: Date; - updatedAt?: Date; - } = { - max: -1, - current: -1, - }; - - constructor(public vehicleConfig: VehicleRegisterOptions, public controller: EuropeanController) { - super(vehicleConfig, controller); - logger.debug(`EU Vehicle ${this.vehicleConfig.id} created`); + public region = REGIONS.EU; + public serverRates: { + max: number; + current: number; + reset?: Date; + updatedAt?: Date; + } = { + max: -1, + current: -1, + }; + + constructor(public vehicleConfig: VehicleRegisterOptions, public controller: EuropeanController) { + super(vehicleConfig, controller); + logger.debug(`EU Vehicle ${this.vehicleConfig.id} created`); + } + + public async start(config: VehicleClimateOptions): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/temperature`, { + body: { + action: 'start', + hvacType: 0, + options: { + defrost: config.defrost, + heating1: config.windscreenHeating ? 1 : 0, + }, + tempCode: celciusToTempCode(REGIONS.EU, config.temperature), + unit: config.unit, + }, + }) + ); + logger.info(`Climate started for vehicle ${this.vehicleConfig.id}`); + return response.body; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.start'); } - - public async start(config: VehicleClimateOptions): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/temperature`, { - body: { - action: 'start', - hvacType: 0, - options: { - defrost: config.defrost, - heating1: config.windscreenHeating ? 1 : 0, - }, - tempCode: celciusToTempCode(REGIONS.EU, config.temperature), - unit: config.unit, - }, - }) - ); - logger.info(`Climate started for vehicle ${this.vehicleConfig.id}`); - return response.body; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.start'); - } + } + + public async stop(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/temperature`, { + body: { + action: 'stop', + hvacType: 0, + options: { + defrost: true, + heating1: 1, + }, + tempCode: '10H', + unit: 'C', + }, + }) + ); + logger.info(`Climate stopped for vehicle ${this.vehicleConfig.id}`); + return response.body; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.stop'); } - - public async stop(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/temperature`, { - body: { - action: 'stop', - hvacType: 0, - options: { - defrost: true, - heating1: 1, - }, - tempCode: '10H', - unit: 'C', - }, - }) - ); - logger.info(`Climate stopped for vehicle ${this.vehicleConfig.id}`); - return response.body; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.stop'); - } + } + + public async lock(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/door`, { + body: { + action: 'close', + deviceId: this.controller.session.deviceId, + }, + }) + ); + if (response.statusCode === 200) { + logger.debug(`Vehicle ${this.vehicleConfig.id} locked`); + return 'Lock successful'; + } + return 'Something went wrong!'; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.lock'); } - - public async lock(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/door`, { - body: { - action: 'close', - deviceId: this.controller.session.deviceId, - }, - }) - ); - if (response.statusCode === 200) { - logger.debug(`Vehicle ${this.vehicleConfig.id} locked`); - return 'Lock successful'; - } - return 'Something went wrong!'; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.lock'); - } + } + + public async unlock(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/door`, { + body: { + action: 'open', + deviceId: this.controller.session.deviceId, + }, + }) + ); + + if (response.statusCode === 200) { + logger.debug(`Vehicle ${this.vehicleConfig.id} unlocked`); + return 'Unlock successful'; + } + + return 'Something went wrong!'; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.unlock'); } - - public async unlock(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/door`, { - body: { - action: 'open', - deviceId: this.controller.session.deviceId, - }, - }) - ); - - if (response.statusCode === 200) { - logger.debug(`Vehicle ${this.vehicleConfig.id} unlocked`); - return 'Unlock successful'; - } - - return 'Something went wrong!'; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.unlock'); - } + } + + public async fullStatus(input: VehicleStatusOptions): Promise { + const statusConfig = { + ...DEFAULT_VEHICLE_STATUS_OPTIONS, + ...input, + }; + + const http = await this.controller.getVehicleHttpService(); + + try { + const cachedResponse = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status/latest`) + ); + + const fullStatus = cachedResponse.body.resMsg.vehicleStatusInfo; + + if (statusConfig.refresh) { + const statusResponse = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status`) + ); + fullStatus.vehicleStatus = statusResponse.body.resMsg; + + const locationResponse = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location`) + ); + fullStatus.vehicleLocation = locationResponse.body.resMsg.gpsDetail; + } + + this._fullStatus = fullStatus; + return this._fullStatus; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.fullStatus'); } - - public async fullStatus(input: VehicleStatusOptions): Promise { - const statusConfig = { - ...DEFAULT_VEHICLE_STATUS_OPTIONS, - ...input, - }; - - const http = await this.controller.getVehicleHttpService(); - - try { - const cachedResponse = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status/latest`) - ); - - const fullStatus = cachedResponse.body.resMsg.vehicleStatusInfo; - - if (statusConfig.refresh) { - const statusResponse = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status`) - ); - fullStatus.vehicleStatus = statusResponse.body.resMsg; - - const locationResponse = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location`) - ); - fullStatus.vehicleLocation = locationResponse.body.resMsg.gpsDetail; - } - - this._fullStatus = fullStatus; - return this._fullStatus; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.fullStatus'); + } + + public async status( + input: VehicleStatusOptions + ): Promise { + const statusConfig = { + ...DEFAULT_VEHICLE_STATUS_OPTIONS, + ...input, + }; + + const http = await this.controller.getVehicleHttpService(); + + try { + const cacheString = statusConfig.refresh ? '' : '/latest'; + + const response = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status${cacheString}`) + ); + + // handles refreshing data + const vehicleStatus = statusConfig.refresh + ? response.body.resMsg + : response.body.resMsg.vehicleStatusInfo.vehicleStatus; + + const parsedStatus: VehicleStatus = { + chassis: { + hoodOpen: vehicleStatus?.hoodOpen, + trunkOpen: vehicleStatus?.trunkOpen, + locked: vehicleStatus.doorLock, + openDoors: { + frontRight: !!vehicleStatus?.doorOpen?.frontRight, + frontLeft: !!vehicleStatus?.doorOpen?.frontLeft, + backLeft: !!vehicleStatus?.doorOpen?.backLeft, + backRight: !!vehicleStatus?.doorOpen?.backRight, + }, + tirePressureWarningLamp: { + rearLeft: !!vehicleStatus?.tirePressureLamp?.tirePressureLampRL, + frontLeft: !!vehicleStatus?.tirePressureLamp?.tirePressureLampFL, + frontRight: !!vehicleStatus?.tirePressureLamp?.tirePressureLampFR, + rearRight: !!vehicleStatus?.tirePressureLamp?.tirePressureLampRR, + all: !!vehicleStatus?.tirePressureLamp?.tirePressureWarningLampAll, + }, + }, + climate: { + active: vehicleStatus?.airCtrlOn, + steeringwheelHeat: !!vehicleStatus?.steerWheelHeat, + sideMirrorHeat: false, + rearWindowHeat: !!vehicleStatus?.sideBackWindowHeat, + defrost: vehicleStatus?.defrost, + temperatureSetpoint: tempCodeToCelsius(REGIONS.EU, vehicleStatus?.airTemp?.value), + temperatureUnit: vehicleStatus?.airTemp?.unit, + }, + engine: { + ignition: vehicleStatus.engine, + accessory: vehicleStatus?.acc, + rangeGas: + vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.gasModeRange?.value ?? + vehicleStatus?.dte?.value, + // EV + range: vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.totalAvailableRange?.value, + rangeEV: vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.evModeRange?.value, + plugedTo: vehicleStatus?.evStatus?.batteryPlugin ?? EVPlugTypes.UNPLUGED, + charging: vehicleStatus?.evStatus?.batteryCharge, + estimatedCurrentChargeDuration: vehicleStatus?.evStatus?.remainTime2?.atc?.value, + estimatedFastChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc1?.value, + estimatedPortableChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc2?.value, + estimatedStationChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc3?.value, + batteryCharge12v: vehicleStatus?.battery?.batSoc, + batteryChargeHV: vehicleStatus?.evStatus?.batteryStatus, + }, + lastupdate: vehicleStatus?.time ? parseDate(vehicleStatus?.time) : null, + }; + + if (!parsedStatus.engine.range) { + if (parsedStatus.engine.rangeEV || parsedStatus.engine.rangeGas) { + parsedStatus.engine.range = + (parsedStatus.engine.rangeEV ?? 0) + (parsedStatus.engine.rangeGas ?? 0); } - } - - public async status( - input: VehicleStatusOptions - ): Promise { - const statusConfig = { - ...DEFAULT_VEHICLE_STATUS_OPTIONS, - ...input, - }; - - const http = await this.controller.getVehicleHttpService(); - - try { - const cacheString = statusConfig.refresh ? '' : '/latest'; - - const response = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status${cacheString}`) - ); - - // handles refreshing data - const vehicleStatus = statusConfig.refresh - ? response.body.resMsg - : response.body.resMsg.vehicleStatusInfo.vehicleStatus; - - const parsedStatus: VehicleStatus = { - chassis: { - hoodOpen: vehicleStatus?.hoodOpen, - trunkOpen: vehicleStatus?.trunkOpen, - locked: vehicleStatus.doorLock, - openDoors: { - frontRight: !!vehicleStatus?.doorOpen?.frontRight, - frontLeft: !!vehicleStatus?.doorOpen?.frontLeft, - backLeft: !!vehicleStatus?.doorOpen?.backLeft, - backRight: !!vehicleStatus?.doorOpen?.backRight, - }, - tirePressureWarningLamp: { - rearLeft: !!vehicleStatus?.tirePressureLamp?.tirePressureLampRL, - frontLeft: !!vehicleStatus?.tirePressureLamp?.tirePressureLampFL, - frontRight: !!vehicleStatus?.tirePressureLamp?.tirePressureLampFR, - rearRight: !!vehicleStatus?.tirePressureLamp?.tirePressureLampRR, - all: !!vehicleStatus?.tirePressureLamp?.tirePressureWarningLampAll, - }, - }, - climate: { - active: vehicleStatus?.airCtrlOn, - steeringwheelHeat: !!vehicleStatus?.steerWheelHeat, - sideMirrorHeat: false, - rearWindowHeat: !!vehicleStatus?.sideBackWindowHeat, - defrost: vehicleStatus?.defrost, - temperatureSetpoint: tempCodeToCelsius(REGIONS.EU, vehicleStatus?.airTemp?.value), - temperatureUnit: vehicleStatus?.airTemp?.unit, - }, - engine: { - ignition: vehicleStatus.engine, - accessory: vehicleStatus?.acc, - rangeGas: - vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.gasModeRange?.value ?? - vehicleStatus?.dte?.value, - // EV - range: vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.totalAvailableRange?.value, - rangeEV: vehicleStatus?.evStatus?.drvDistance[0]?.rangeByFuel?.evModeRange?.value, - plugedTo: vehicleStatus?.evStatus?.batteryPlugin ?? EVPlugTypes.UNPLUGED, - charging: vehicleStatus?.evStatus?.batteryCharge, - estimatedCurrentChargeDuration: vehicleStatus?.evStatus?.remainTime2?.atc?.value, - estimatedFastChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc1?.value, - estimatedPortableChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc2?.value, - estimatedStationChargeDuration: vehicleStatus?.evStatus?.remainTime2?.etc3?.value, - batteryCharge12v: vehicleStatus?.battery?.batSoc, - batteryChargeHV: vehicleStatus?.evStatus?.batteryStatus, - }, - lastupdate: vehicleStatus?.time ? parseDate(vehicleStatus?.time) : null, - }; - - if (!parsedStatus.engine.range) { - if (parsedStatus.engine.rangeEV || parsedStatus.engine.rangeGas) { - parsedStatus.engine.range = - (parsedStatus.engine.rangeEV ?? 0) + (parsedStatus.engine.rangeGas ?? 0); - } - } + } - this._status = statusConfig.parsed ? parsedStatus : vehicleStatus; + this._status = statusConfig.parsed ? parsedStatus : vehicleStatus; - return this._status; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.status'); - } + return this._status; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.status'); } - - public async odometer(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status/latest`) - ); - this._odometer = response.body.resMsg.vehicleStatusInfo.odometer as VehicleOdometer; - return this._odometer; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.odometer'); - } + } + + public async odometer(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/status/latest`) + ); + this._odometer = response.body.resMsg.vehicleStatusInfo.odometer as VehicleOdometer; + return this._odometer; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.odometer'); } - - public async location(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location`) - ); - - const data = response.body.resMsg?.gpsDetail ?? response.body.resMsg; - this._location = { - latitude: data?.coord?.lat, - longitude: data?.coord?.lon, - altitude: data?.coord?.alt, - speed: { - unit: data?.speed?.unit, - value: data?.speed?.value, - }, - heading: data?.head, - }; - - return this._location; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.location'); - } + } + + public async location(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location`) + ); + + const data = response.body.resMsg?.gpsDetail ?? response.body.resMsg; + this._location = { + latitude: data?.coord?.lat, + longitude: data?.coord?.lon, + altitude: data?.coord?.alt, + speed: { + unit: data?.speed?.unit, + value: data?.speed?.value, + }, + heading: data?.head, + }; + + return this._location; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.location'); } - - public async startCharge(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/charge`, { - body: { - action: 'start', - deviceId: this.controller.session.deviceId, - }, - }) - ); - - if (response.statusCode === 200) { - logger.debug(`Send start charge command to Vehicle ${this.vehicleConfig.id}`); - return 'Start charge successful'; - } - - throw 'Something went wrong!'; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.startCharge'); - } + } + + public async startCharge(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/charge`, { + body: { + action: 'start', + deviceId: this.controller.session.deviceId, + }, + }) + ); + + if (response.statusCode === 200) { + logger.debug(`Send start charge command to Vehicle ${this.vehicleConfig.id}`); + return 'Start charge successful'; + } + + throw 'Something went wrong!'; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.startCharge'); + } + } + + public async stopCharge(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/charge`, { + body: { + action: 'stop', + deviceId: this.controller.session.deviceId, + }, + }) + ); + + if (response.statusCode === 200) { + logger.debug(`Send stop charge command to Vehicle ${this.vehicleConfig.id}`); + return 'Stop charge successful'; + } + + throw 'Something went wrong!'; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.stopCharge'); } + } - public async stopCharge(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/charge`, { - body: { - action: 'stop', - deviceId: this.controller.session.deviceId, - }, - }) - ); - - if (response.statusCode === 200) { - logger.debug(`Send stop charge command to Vehicle ${this.vehicleConfig.id}`); - return 'Stop charge successful'; + public async monthlyReport( + month: { year: number; month: number } = { + year: new Date().getFullYear(), + month: new Date().getMonth() + 1, + } + ): Promise | undefined> { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/monthlyreport`, { + body: { + setRptMonth: toMonthDate(month), + }, + }) + ); + const rawData = response.body.resMsg?.monthlyReport; + if (rawData) { + return { + start: rawData.ifo?.mvrMonthStart, + end: rawData.ifo?.mvrMonthEnd, + breakdown: rawData.breakdown, + driving: rawData.driving + ? { + distance: rawData.driving?.runDistance, + startCount: rawData.driving?.engineStartCount, + durations: { + idle: rawData.driving?.engineIdleTime, + drive: rawData.driving?.engineOnTime, + }, } - - throw 'Something went wrong!'; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.stopCharge'); - } + : undefined, + vehicleStatus: rawData.vehicleStatus + ? { + tpms: rawData.vehicleStatus?.tpmsSupport + ? Boolean(rawData.vehicleStatus?.tpmsSupport) + : undefined, + tirePressure: { + all: rawData.vehicleStatus?.tirePressure?.tirePressureLampAll == '1', + }, + } + : undefined, + }; + } + return; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.monthyReports'); } - - public async monthlyReport( - month: { year: number; month: number } = { - year: new Date().getFullYear(), - month: new Date().getMonth() + 1, - } - ): Promise | undefined> { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/monthlyreport`, { - body: { - setRptMonth: toMonthDate(month), - }, - }) - ); - const rawData = response.body.resMsg?.monthlyReport; - if (rawData) { + } + + public async tripInfo(date: { + year: number; + month: number; + day: number; + }): Promise[] | undefined>; + public async tripInfo(date?: { + year: number; + month: number; + }): Promise | undefined>; + + public async tripInfo( + date: { year: number; month: number; day?: number } = { + year: new Date().getFullYear(), + month: new Date().getMonth() + 1, + } + ): Promise[] | DeepPartial | undefined> { + const http = await this.controller.getApiHttpService(); + try { + const perDay = Boolean(date.day); + const response = this.updateRates( + await http.post(`/api/v1/spa/vehicles/${this.vehicleConfig.id}/tripinfo`, { + body: { + setTripLatest: 10, + setTripMonth: !perDay ? toMonthDate(date) : undefined, + setTripDay: perDay ? toDayDate(date) : undefined, + tripPeriodType: perDay ? 1 : 0, + }, + }) + ); + + if (!perDay) { + const rawData = response.body.resMsg; + return { + days: Array.isArray(rawData?.tripDayList) + ? rawData?.tripDayList.map(day => ({ + dayRaw: day.tripDayInMonth, + date: day.tripDayInMonth ? parseDate(day.tripDayInMonth) : undefined, + tripsCount: day.tripCntDay, + })) + : [], + durations: { + drive: rawData?.tripDrvTime, + idle: rawData?.tripIdleTime, + }, + distance: rawData?.tripDist, + speed: { + avg: rawData?.tripAvgSpeed, + max: rawData?.tripMaxSpeed, + }, + } as VehicleMonthTrip; + } else { + const rawData = response.body.resMsg.dayTripList; + if (rawData && Array.isArray(rawData)) { + return rawData.map(day => ({ + dayRaw: day.tripDay, + tripsCount: day.dayTripCnt, + distance: day.tripDist, + durations: { + drive: day.tripDrvTime, + idle: day.tripIdleTime, + }, + speed: { + avg: day.tripAvgSpeed, + max: day.tripMaxSpeed, + }, + trips: Array.isArray(day.tripList) + ? day.tripList.map(trip => { + const start = parseDate(`${day.tripDay}${trip.tripTime}`); return { - start: rawData.ifo?.mvrMonthStart, - end: rawData.ifo?.mvrMonthEnd, - breakdown: rawData.breakdown, - driving: rawData.driving - ? { - distance: rawData.driving?.runDistance, - startCount: rawData.driving?.engineStartCount, - durations: { - idle: rawData.driving?.engineIdleTime, - drive: rawData.driving?.engineOnTime, - }, - } - : undefined, - vehicleStatus: rawData.vehicleStatus - ? { - tpms: rawData.vehicleStatus?.tpmsSupport - ? Boolean(rawData.vehicleStatus?.tpmsSupport) - : undefined, - tirePressure: { - all: rawData.vehicleStatus?.tirePressure?.tirePressureLampAll == '1', - }, - } - : undefined, + timeRaw: trip.tripTime, + start, + end: addMinutes(start, trip.tripDrvTime), + durations: { + drive: trip.tripDrvTime, + idle: trip.tripIdleTime, + }, + speed: { + avg: trip.tripAvgSpeed, + max: trip.tripMaxSpeed, + }, + distance: trip.tripDist, }; - } - return; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.monthyReports'); + }) + : [], + })); } + } + return; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.history'); } - - public async tripInfo(date: { - year: number; - month: number; - day: number; - }): Promise[] | undefined>; - public async tripInfo(date?: { - year: number; - month: number; - }): Promise | undefined>; - - public async tripInfo( - date: { year: number; month: number; day?: number } = { - year: new Date().getFullYear(), - month: new Date().getMonth() + 1, - } - ): Promise[] | DeepPartial | undefined> { - const http = await this.controller.getApiHttpService(); - try { - const perDay = Boolean(date.day); - const response = this.updateRates( - await http.post(`/api/v1/spa/vehicles/${this.vehicleConfig.id}/tripinfo`, { - body: { - setTripLatest: 10, - setTripMonth: !perDay ? toMonthDate(date) : undefined, - setTripDay: perDay ? toDayDate(date) : undefined, - tripPeriodType: perDay ? 1 : 0, - }, - }) - ); - - if (!perDay) { - const rawData = response.body.resMsg; - return { - days: Array.isArray(rawData?.tripDayList) - ? rawData?.tripDayList.map(day => ({ - dayRaw: day.tripDayInMonth, - date: day.tripDayInMonth ? parseDate(day.tripDayInMonth) : undefined, - tripsCount: day.tripCntDay, - })) - : [], - durations: { - drive: rawData?.tripDrvTime, - idle: rawData?.tripIdleTime, - }, - distance: rawData?.tripDist, - speed: { - avg: rawData?.tripAvgSpeed, - max: rawData?.tripMaxSpeed, - }, - } as VehicleMonthTrip; - } else { - const rawData = response.body.resMsg.dayTripList; - if (rawData && Array.isArray(rawData)) { - return rawData.map(day => ({ - dayRaw: day.tripDay, - tripsCount: day.dayTripCnt, - distance: day.tripDist, - durations: { - drive: day.tripDrvTime, - idle: day.tripIdleTime, - }, - speed: { - avg: day.tripAvgSpeed, - max: day.tripMaxSpeed, - }, - trips: Array.isArray(day.tripList) - ? day.tripList.map(trip => { - const start = parseDate(`${day.tripDay}${trip.tripTime}`); - return { - timeRaw: trip.tripTime, - start, - end: addMinutes(start, trip.tripDrvTime), - durations: { - drive: trip.tripDrvTime, - idle: trip.tripIdleTime, - }, - speed: { - avg: trip.tripAvgSpeed, - max: trip.tripMaxSpeed, - }, - distance: trip.tripDist, - }; - }) - : [], - })); - } - } - return; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.history'); - } + } + + public async driveHistory(period: historyDrivingPeriod = historyDrivingPeriod.DAY): Promise< + DeepPartial<{ + cumulated: EUDriveHistory[]; + history: EUDatedDriveHistory[]; + }> + > { + const http = await this.controller.getApiHttpService(); + try { + const response = await http.post(`/api/v1/spa/vehicles/${this.vehicleConfig.id}/drvhistory`, { + body: { + periodTarget: period, + }, + }); + return { + cumulated: response.body.resMsg.drivingInfo.map(line => ({ + period: line.drivingPeriod, + consumption: { + total: line.totalPwrCsp, + engine: line.motorPwrCsp, + climate: line.climatePwrCsp, + devices: line.eDPwrCsp, + battery: line.batteryMgPwrCsp, + }, + regen: line.regenPwr, + distance: line.calculativeOdo, + })), + history: response.body.resMsg.drivingInfoDetail.map(line => ({ + period: line.drivingPeriod, + rawDate: line.drivingDate, + date: line.drivingDate ? parseDate(line.drivingDate) : undefined, + consumption: { + total: line.totalPwrCsp, + engine: line.motorPwrCsp, + climate: line.climatePwrCsp, + devices: line.eDPwrCsp, + battery: line.batteryMgPwrCsp, + }, + regen: line.regenPwr, + distance: line.calculativeOdo, + })), + }; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.history'); } - - public async driveHistory(period: historyDrivingPeriod = historyDrivingPeriod.DAY): Promise< - DeepPartial<{ - cumulated: EUDriveHistory[]; - history: EUDatedDriveHistory[]; - }> - > { - const http = await this.controller.getApiHttpService(); - try { - const response = await http.post(`/api/v1/spa/vehicles/${this.vehicleConfig.id}/drvhistory`, { - body: { - periodTarget: period, - }, - }); - return { - cumulated: response.body.resMsg.drivingInfo.map(line => ({ - period: line.drivingPeriod, - consumption: { - total: line.totalPwrCsp, - engine: line.motorPwrCsp, - climate: line.climatePwrCsp, - devices: line.eDPwrCsp, - battery: line.batteryMgPwrCsp, - }, - regen: line.regenPwr, - distance: line.calculativeOdo, - })), - history: response.body.resMsg.drivingInfoDetail.map(line => ({ - period: line.drivingPeriod, - rawDate: line.drivingDate, - date: line.drivingDate ? parseDate(line.drivingDate) : undefined, - consumption: { - total: line.totalPwrCsp, - engine: line.motorPwrCsp, - climate: line.climatePwrCsp, - devices: line.eDPwrCsp, - battery: line.batteryMgPwrCsp, - }, - regen: line.regenPwr, - distance: line.calculativeOdo, - })), - }; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.history'); - } + } + + /** + * Warning: Only works on EV + */ + public async getChargeTargets(): Promise[] | undefined> { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates( + await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/charge/target`) + ); + const rawData = response.body.resMsg?.targetSOClist; + if (rawData && Array.isArray(rawData)) { + return rawData.map(rawSOC => ({ + distance: rawSOC.drvDistance?.distanceType?.distanceValue, + targetLevel: rawSOC.targetSOClevel, + type: rawSOC.plugType, + })); + } + return; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.getChargeTargets'); } - - /** - * Warning: Only works on EV - */ - public async getChargeTargets(): Promise[] | undefined> { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates( - await http.get(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/charge/target`) - ); - const rawData = response.body.resMsg?.targetSOClist; - if (rawData && Array.isArray(rawData)) { - return rawData.map(rawSOC => ({ - distance: rawSOC.drvDistance?.distanceType?.distanceValue, - targetLevel: rawSOC.targetSOClevel, - type: rawSOC.plugType, - })); - } - return; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.getChargeTargets'); - } + } + + /** + * Warning: Only works on EV + */ + public async setChargeTargets(limits: { fast: ChargeTarget; slow: ChargeTarget }): Promise { + const http = await this.controller.getVehicleHttpService(); + 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(', ')}` + ); } - - /** - * Warning: Only works on EV - */ - public async setChargeTargets(limits: { fast: ChargeTarget; slow: ChargeTarget }): Promise { - const http = await this.controller.getVehicleHttpService(); - 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(', ')}` - ); - } - try { - this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/charge/target`, { - body: { - targetSOClist: [ - { plugType: EVChargeModeTypes.FAST, targetSOClevel: limits.fast }, - { plugType: EVChargeModeTypes.SLOW, targetSOClevel: limits.slow }, - ], - }, - }) - ); - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.setChargeTargets'); - } + try { + this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/charge/target`, { + body: { + targetSOClist: [ + { plugType: EVChargeModeTypes.FAST, targetSOClevel: limits.fast }, + { plugType: EVChargeModeTypes.SLOW, targetSOClevel: limits.slow }, + ], + }, + }) + ); + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.setChargeTargets'); } - - /** - * Define a navigation route - * @param poiInformations The list of POIs and waypoint to go through - */ - public async setNavigation(poiInformations: EUPOIInformation[]): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - this.updateRates( - await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location/routes`, { - body: { - deviceID: this.controller.session.deviceId, - poiInfoList: poiInformations, - }, - }) - ); - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.setNavigation'); - } + } + + /** + * Define a navigation route + * @param poiInformations The list of POIs and waypoint to go through + */ + public async setNavigation(poiInformations: EUPOIInformation[]): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + this.updateRates( + await http.post(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/location/routes`, { + body: { + deviceID: this.controller.session.deviceId, + poiInfoList: poiInformations, + }, + }) + ); + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.setNavigation'); } - - - public async getChargeSchedule(): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates(await http.get( - `/api/v2/spa/vehicles/${this.vehicleConfig.id}/reservation/charge`)); - const result = response.body.resMsg as ReservationCharge; - return result; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.getChargeSchedule'); - } + } + + + public async getChargeSchedule(): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates(await http.get( + `/api/v2/spa/vehicles/${this.vehicleConfig.id}/reservation/charge`)); + const result = response.body.resMsg as ReservationCharge; + return result; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.getChargeSchedule'); } + } + + /** Warning: doesn't work yet. + * Returns a 503 error when called, + * even when Android app works fine */ + public async setChargeSchedule(schedule: ReservationCharge): Promise { + const http = await this.controller.getVehicleHttpService(); + try { + const response = this.updateRates(await http.post( + `/api/v2/spa/vehicles/${this.vehicleConfig.id}/reservation/charge`, { + body: schedule + }) + ); + return response; + } catch (err) { + throw manageBluelinkyError(err, 'EuropeVehicle.setChargeSchedule'); - /** Warning: doesn't work yet. - * Returns a 503 error when called, - * even when Android app works fine */ - public async setChargeSchedule(schedule: ReservationCharge): Promise { - const http = await this.controller.getVehicleHttpService(); - try { - const response = this.updateRates(await http.post( - `/api/v2/spa/vehicles/${this.vehicleConfig.id}/reservation/charge`, { - body: schedule - }) - ); - return response; - } catch (err) { - throw manageBluelinkyError(err, 'EuropeVehicle.setChargeSchedule'); - - } } - - private updateRates>(resp: got.Response): got.Response { - if (resp.headers?.['x-ratelimit-limit']) { - this.serverRates.max = Number(resp.headers?.['x-ratelimit-limit']); - this.serverRates.current = Number(resp.headers?.['x-ratelimit-remaining']); - if (resp.headers?.['x-ratelimit-reset']) { - this.serverRates.reset = new Date(Number(`${resp.headers?.['x-ratelimit-reset']}000`)); - } - this.serverRates.updatedAt = new Date(); - } - return resp; + } + + private updateRates>(resp: got.Response): got.Response { + if (resp.headers?.['x-ratelimit-limit']) { + this.serverRates.max = Number(resp.headers?.['x-ratelimit-limit']); + this.serverRates.current = Number(resp.headers?.['x-ratelimit-remaining']); + if (resp.headers?.['x-ratelimit-reset']) { + this.serverRates.reset = new Date(Number(`${resp.headers?.['x-ratelimit-reset']}000`)); + } + this.serverRates.updatedAt = new Date(); } + return resp; + } } function toMonthDate(month: { year: number; month: number }) { - return `${month.year}${month.month.toString().padStart(2, '0')}`; + return `${month.year}${month.month.toString().padStart(2, '0')}`; } function toDayDate(date: { year: number; month: number; day?: number }) { - return date.day - ? `${toMonthDate(date)}${date.day.toString().padStart(2, '0')}` - : toMonthDate(date); + return date.day + ? `${toMonthDate(date)}${date.day.toString().padStart(2, '0')}` + : toMonthDate(date); }