homebridge-bold
Version:
HomeKit support for the Bold Smart Locks.
171 lines (170 loc) • 9.14 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BoldPlatform = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const bold_1 = require("./bold");
const types_1 = require("./types");
const const_1 = require("./const");
const lock_accessory_1 = require("./accessories/lock-accessory");
const switch_accessory_1 = require("./accessories/switch-accessory");
exports.default = (api) => {
api.registerPlatform(const_1.PLATFORM_NAME, BoldPlatform);
};
class BoldPlatform {
constructor(log, config, api) {
this.log = log;
this.api = api;
this.accessories = [];
this.hap = api.hap;
this.config = config;
this.bold = new bold_1.BoldAPI(this.config, this.log);
api.on("didFinishLaunching" /* DID_FINISH_LAUNCHING */, () => __awaiter(this, void 0, void 0, function* () {
yield this.refreshAccessToken();
yield this.updateDevices();
this.refreshInterval = setInterval(() => __awaiter(this, void 0, void 0, function* () {
yield this.refreshAccessToken();
yield this.updateDevices();
}), 24 * 60 * 60 * 1000);
}));
api.on("shutdown" /* SHUTDOWN */, () => {
if (this.refreshInterval != null) {
clearInterval(this.refreshInterval);
}
});
}
// Accessories
isSwitchAccessory(device) {
return device.type.id == types_1.DeviceType.Connect && !this.config.showControllerAsLock;
}
configureAccessory(accessory) {
let device = accessory.context.device;
if (!device) {
this.log.warn(`Device not found for accessory ${accessory.UUID}. Removing...`);
this.removeAccessory(accessory);
return;
}
if (accessory.context.isSwitchAccessory) {
new switch_accessory_1.SwitchAccessory(this, accessory, device);
}
else {
new lock_accessory_1.LockAccessory(this, accessory, device);
}
this.accessories.push(accessory);
}
addAccessory(device) {
let accessory;
// Separate UUIDs for lock and switch in case the config option is changed when the device already exists.
if (this.isSwitchAccessory(device)) {
let uuid = this.hap.uuid.generate(`BoldSwitch${device.id}`);
accessory = new this.api.platformAccessory(device.name, uuid, 8 /* SWITCH */);
accessory.context.isSwitchAccessory = true;
}
else {
let uuid = this.hap.uuid.generate(`BoldLock${device.id}`);
accessory = new this.api.platformAccessory(device.name, uuid, 6 /* DOOR_LOCK */);
accessory.context.isSwitchAccessory = false;
}
accessory.context.device = device;
// Services & Characteristics initialized by configureAccessory()
this.configureAccessory(accessory);
this.api.registerPlatformAccessories(const_1.PLUGIN_NAME, const_1.PLATFORM_NAME, [accessory]);
}
removeAccessory(accessory) {
let index = this.accessories.indexOf(accessory);
delete this.accessories[index];
this.api.unregisterPlatformAccessories(const_1.PLUGIN_NAME, const_1.PLATFORM_NAME, [accessory]);
}
// Bold API
updateDevices() {
return __awaiter(this, void 0, void 0, function* () {
let devices;
try {
devices = yield this.bold.getDevices();
}
catch (error) {
if (this.accessories.length == 0) {
this.log.error('Unable to get devices. Check your authentication details.');
}
else {
this.log.warn('Unable to refresh devices. Preserving cached accessories, which might be incorrect. Check your authentication details.');
}
return;
}
// Add devices
let addDevices = devices.filter((device) => !this.accessories.find((accessory) => accessory.context.device.id == device.id && accessory.context.isSwitchAccessory == this.isSwitchAccessory(device)));
if (addDevices.length > 0)
this.log.info(`Found ${addDevices.length} new device${addDevices.length != 1 ? 's' : ''} supporting remote activation.`);
addDevices.forEach(this.addAccessory.bind(this));
// Remove devices
let removeAccessories = this.accessories.filter((accessory) => !devices.find((device) => accessory.context.device.id == device.id && accessory.context.isSwitchAccessory == this.isSwitchAccessory(device)));
if (removeAccessories.length > 0)
this.log.info(`Removing ${removeAccessories.length} old device${removeAccessories.length != 1 ? 's' : ''}.`);
removeAccessories.forEach(this.removeAccessory.bind(this));
// Update existing devices
for (let accessory of this.accessories.filter((accessory) => devices.find((device) => accessory.context.device.id == device.id && accessory.context.isSwitchAccessory == this.isSwitchAccessory(device)))) {
accessory.context.device = devices.find((device) => device.id == accessory.context.device.id);
this.api.updatePlatformAccessories(this.accessories);
}
});
}
refreshAccessToken() {
return __awaiter(this, void 0, void 0, function* () {
let config;
try {
config = yield fs_extra_1.default.readJSON(this.api.user.configPath());
}
catch (error) {
this.log.error(`Error while reading config for access token refresh: ${error}`);
return;
}
let platformIndex = config.platforms.findIndex((platform) => platform.platform == const_1.PLATFORM_NAME && platform.accessToken == this.bold.config.accessToken);
let hasWarned = false;
if (platformIndex == -1) {
this.log.warn("Warning while reading config for access token refresh: Couldn't find platform with current access token. Using first entry of Bold config.");
hasWarned = true;
platformIndex = config.platforms.findIndex((platform) => platform.platform == const_1.PLATFORM_NAME);
}
if (platformIndex == -1) {
this.log.error("Error while reading config for access token refresh: Couldn't find entry of Bold platform. Skipping token refresh.");
return;
}
let refreshedTokens = yield this.bold.refresh();
if (!refreshedTokens) {
return;
}
// Reloading config in case it was updated while refreshing
try {
config = yield fs_extra_1.default.readJSON(this.api.user.configPath());
}
catch (error) {
this.log.error(`Error while reading config for access token refresh: ${error}`);
return;
}
platformIndex = config.platforms.findIndex((platform) => platform.platform == const_1.PLATFORM_NAME && platform.accessToken == this.bold.config.accessToken);
if (platformIndex == -1 && !hasWarned) {
this.log.warn("Warning while reading config for access token refresh: Couldn't find platform with current access token. Using first entry of Bold config.");
platformIndex = config.platforms.findIndex((platform) => platform.platform == const_1.PLATFORM_NAME);
}
if (platformIndex == -1) {
this.log.error("Error while reading config for access token refresh: Couldn't find entry of Bold platform. Skipping token refresh.");
}
config.platforms[platformIndex].accessToken = refreshedTokens.accessToken;
config.platforms[platformIndex].refreshToken = refreshedTokens.refreshToken;
yield fs_extra_1.default.writeJSON(this.api.user.configPath(), config, { spaces: 4 });
this.bold.config = Object.assign(Object.assign({}, this.bold.config), { accessToken: refreshedTokens.accessToken, refreshToken: refreshedTokens.refreshToken });
});
}
}
exports.BoldPlatform = BoldPlatform;