Skip to content

Commit b9104f5

Browse files
committed
Catch errors in constructor
1 parent b3ec87c commit b9104f5

File tree

2 files changed

+55
-27
lines changed

2 files changed

+55
-27
lines changed

src/index.ts

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,49 +14,63 @@ export default function (homebridge: HomebridgeAPI) {
1414
homebridge.registerAccessory("homebridge-volvo", "Volvo", VolvoPlatform);
1515
}
1616

17-
class VolvoPlatform extends REST {
18-
private readonly config: Config;
19-
private readonly sensorNames: SensorNames;
20-
21-
private vehicle: Vehicle;
17+
class VolvoPlatform {
18+
// Definite assignment required since callee-thrown errors are not handled by caller/homebridge.
19+
// If constructor runs without errors, all members will be assigned. :)
20+
private readonly config!: Config;
21+
private readonly sensorNames!: SensorNames;
22+
private readonly rest!: REST;
23+
private vehicle!: Vehicle;
2224
private vehicleCount = 0;
23-
private readonly _BASENAME: string;
25+
private readonly _BASENAME!: string;
2426
private AccessoryInformationService;
27+
private hasFatalError = false; // error flag for homebridge registration
2528

2629
constructor(private readonly log: Logger, accessoryConfig: AccessoryConfig, private readonly api: API) {
27-
super(getConfig(accessoryConfig));
28-
this.log = log;
29-
this.config = getConfig(accessoryConfig);
30-
this.sensorNames = getSensorNames( accessoryConfig["sensorNames"] && typeof accessoryConfig["sensorNames"] === "object" ? accessoryConfig.sensorNames : {});
31-
this._BASENAME = `${this.config.name} `;
32-
3330
log.info("Starting homebridge-volvo");
34-
35-
this.vehicle = this.GetVehicleSync();
36-
const vehicleModel = `${this.vehicle.attr.modelYear} ${this.vehicle.attr.vehicleType}`;
37-
log.info(
38-
`Got vehicle ${vehicleModel} with registration number ${this.vehicle.attr.registrationNumber}.`,
39-
);
40-
this.AccessoryInformationService = new this.api.hap.Service.AccessoryInformation()
41-
.setCharacteristic(Characteristic.Manufacturer, "Volvo")
42-
.setCharacteristic(Characteristic.SerialNumber, this.vehicle.attr.registrationNumber)
43-
.setCharacteristic(Characteristic.Model, vehicleModel);
31+
try {
32+
this.config = getConfig(accessoryConfig);
33+
this.sensorNames = getSensorNames( accessoryConfig["sensorNames"] && typeof accessoryConfig["sensorNames"] === "object" ? accessoryConfig.sensorNames : {});
34+
this.rest = new REST(this.config);
35+
this._BASENAME = `${this.config.name} `;
36+
this.vehicle = this.GetVehicleSync();
37+
const vehicleModel = `${this.vehicle.attr.modelYear} ${this.vehicle.attr.vehicleType}`;
38+
log.info(
39+
`Got vehicle ${vehicleModel} with registration number ${this.vehicle.attr.registrationNumber}.`,
40+
);
41+
this.AccessoryInformationService = new this.api.hap.Service.AccessoryInformation()
42+
.setCharacteristic(Characteristic.Manufacturer, "Volvo")
43+
.setCharacteristic(Characteristic.SerialNumber, this.vehicle.attr.registrationNumber)
44+
.setCharacteristic(Characteristic.Model, vehicleModel);
45+
46+
} catch (error) {
47+
this.hasFatalError = true;
48+
if (error instanceof Error) {
49+
log.error(`Failed to start homebridge-volvo with ${error.stack || error}`);
50+
} else {
51+
log.error(`Failed to start homebridge-volvo. Error: ${error}`);
52+
}
53+
log.info("Shutting down homebridge-volvo.");
54+
if (this.vehicle) {
55+
this.vehicle.Shutdown();
56+
}
57+
}
4458
}
4559

4660
public GetVehicleSync(): Vehicle {
4761
// Get vehicles associated with user
48-
const user: User = this.GetSync("customeraccounts");
62+
const user: User = this.rest.GetSync("customeraccounts");
4963
this.vehicleCount = user.accountVehicleRelations.length;
5064
this.log.debug(`Got account for ${user["username"]}`);
5165
// Get data and instantiate vehicle class for each vehicle
5266
for (let i = 0; i < this.vehicleCount; i++) {
5367
const vehicle = user.accountVehicleRelations[i];
54-
const rel = this.GetSync("", vehicle);
68+
const rel = this.rest.GetSync("", vehicle);
5569
if (rel["status"] === "Verified") {
5670
const url = rel["vehicle"] + "/";
57-
const attr: VehicleAttributes = this.GetSync("attributes", url);
71+
const attr: VehicleAttributes = this.rest.GetSync("attributes", url);
5872
if (attr.VIN === this.config.VIN || !this.config.VIN) {
59-
const state = this.GetSync("status", url);
73+
const state = this.rest.GetSync("status", url);
6074
return new Vehicle(this.config, url, Characteristic, this.log, attr, state);
6175
}
6276
}
@@ -65,6 +79,10 @@ class VolvoPlatform extends REST {
6579
}
6680

6781
public getServices() {
82+
if (this.hasFatalError) {
83+
return [];
84+
}
85+
6886
const services: IService[] = [this.AccessoryInformationService];
6987

7088
// Feature services

src/util/vehicle.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export class Vehicle extends VehicleApi {
1616
public readonly features: Record<string, boolean> = {};
1717
private lockTargetState: CharacteristicValue;
1818
private bootUnlock = false;
19+
private updateTask: NodeJS.Timeout;
1920

2021
constructor(
2122
private config: Config,
@@ -67,7 +68,7 @@ export class Vehicle extends VehicleApi {
6768
this.log.info(`\nFeatures enabled:\n\t${getFeatures()}`);
6869

6970
// Update periodically.
70-
setInterval(this.Update.bind(this), this.config.updateInterval * 1000);
71+
this.updateTask = setInterval(this.Update.bind(this), this.config.updateInterval * 1000);
7172
}
7273

7374
/**
@@ -394,4 +395,13 @@ export class Vehicle extends VehicleApi {
394395
private async StopPreclimatization() {
395396
return await this.Call("preclimatization/stop");
396397
}
398+
399+
/**
400+
* Clears update task to VOC API.
401+
*/
402+
public Shutdown(): void {
403+
if (this.updateTask) {
404+
clearInterval(this.updateTask);
405+
}
406+
}
397407
}

0 commit comments

Comments
 (0)