homebridge-soma-shades
Version:
A homebridge plugin for SOMA Smart Shades
163 lines • 8.57 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SOMAShadesPlatform = void 0;
const settings_1 = require("./settings");
const platformAccessory_1 = require("./platformAccessory");
const noble_1 = __importDefault(require("@abandonware/noble"));
const somaDevice_1 = require("./somaDevice");
/**
* HomebridgePlatform
* This class is the main constructor for your plugin, this is where you should
* parse the user config and discover/register accessories with Homebridge.
*/
class SOMAShadesPlatform {
constructor(log, config, api) {
this.log = log;
this.config = config;
this.api = api;
this.Service = this.api.hap.Service;
this.Characteristic = this.api.hap.Characteristic;
// this is used to track restored cached accessories
this.accessories = [];
// let our callback know we stopped the scan
this.discoveredAll = false;
this.log.debug('Finished initializing platform');
// When this event is fired it means Homebridge has restored all cached accessories from disk.
// Dynamic Platform plugins should only register new accessories after this event was fired,
// in order to ensure they weren't added to homebridge already. This event can also be used
// to start discovery of new accessories.
this.api.on("didFinishLaunching" /* DID_FINISH_LAUNCHING */, () => {
this.log.debug('on DID_FINISH_LAUNCHING. Looking for new accessories');
// run the method to discover / register your devices as accessories
const discoveryDelay = config.discoverDelay;
this.log.debug(`delay discovery for ${discoveryDelay} seconds`);
setTimeout(() => this.discoverDevices(), discoveryDelay * 1000);
});
}
/**
* This function is invoked when homebridge restores cached accessories from disk at startup.
* It should be used to setup event handlers for characteristics and update respective values.
*/
configureAccessory(accessory) {
this.log.debug('Loading accessory from cache:', accessory.displayName);
// add the restored accessory to the accessories cache so we can track if it has already been registered
this.accessories.push(accessory);
}
discoverDevices() {
// check for config
if (!this.config || !this.config.devices || this.config.devices.length === 0) {
this.log.error('invalid config, removing all accessories');
this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, this.accessories);
return false;
}
// remove invalid accessories
// we're not removing it from cached this.accessories
// because those invalid accessory will not be called with addAccessory
for (const accessory of this.accessories) {
if (!this.config.devices.find((config) => config.id.toLowerCase() === accessory.context.device.id.toLowerCase())) {
this.log.info('%s is not configured, removing...', accessory.displayName);
this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
}
}
const that = this;
const scanStopped = function () {
if (!that.discoveredAll) {
that.log.debug('we have not discovered all configured devices, restarting scan...');
noble_1.default.removeAllListeners('discover');
noble_1.default.on('discover', discoverPeripharels);
noble_1.default.startScanningAsync([], false).catch((error) => {
that.log.error(`failed to start noble scanning: ${error}`);
});
}
};
const discoveredDevices = [];
const discoverPeripharels = function (peripharel) {
if (that.discoveredAll) {
that.log.debug('we have discovered all devices, removing listeners...');
noble_1.default.removeAllListeners('discover');
noble_1.default.removeListener('scanStop', scanStopped);
noble_1.default.stopScanningAsync().catch((error) => {
that.log.error(`failed to stop noble scanning: ${error}`);
});
return true;
}
const peripharelId = peripharel.id.toLowerCase();
if (discoveredDevices.includes(peripharelId)) {
that.log.debug(`peripheral ${peripharelId} has been discovered`);
return true;
}
const deviceConfig = that.config.devices.find((config) => config.id.toLowerCase() === peripharelId);
if (!deviceConfig) {
that.log.debug(`peripheral ${peripharelId} is not in config`);
return false;
}
that.log.info(`discovered peripheral ${peripharelId}, adding to accessories`);
discoveredDevices.push(peripharelId);
that.addAccessory(deviceConfig, peripharel);
if (discoveredDevices.length === that.config.devices.length) {
that.log.info('discovered all peripherals');
that.discoveredAll = true;
noble_1.default.removeAllListeners('discover');
noble_1.default.removeListener('scanStop', scanStopped);
noble_1.default.stopScanningAsync().catch((error) => {
that.log.error(`failed to stop noble scanning: ${error}`);
});
}
return true;
};
// note that soma devices doesn't support scan with service uuid
const startDiscovery = function () {
noble_1.default.once('scanStop', scanStopped);
that.log.debug('start noble scanning');
noble_1.default.on('discover', discoverPeripharels);
noble_1.default.startScanningAsync([], false).catch((error) => {
that.log.error(`failed to start noble scanning: ${error}`);
});
};
if (noble_1.default.state !== 'poweredOn') {
this.log.info('noble is not running. waiting for it to power on...');
noble_1.default.once('stateChange', (state) => {
if (state === 'poweredOn') {
this.log.info('noble is powered on');
startDiscovery();
}
else {
this.log.error(`noble is not powered on but in ${state} state`);
}
});
return true;
}
startDiscovery();
return true;
}
addAccessory(deviceConfig, peripheral) {
const uuid = this.api.hap.uuid.generate(deviceConfig.id);
const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
if (existingAccessory) {
// the accessory already exists
this.log.debug('restoring existing accessory from cache:', existingAccessory.displayName);
new platformAccessory_1.ShadesAccessory(this, existingAccessory, new somaDevice_1.SOMADevice(this.log, peripheral));
// update accessory cache with any changes to the accessory details and information
this.api.updatePlatformAccessories([existingAccessory]);
}
else {
// the accessory does not yet exist, so we need to create it
this.log.debug('adding new accessory:', deviceConfig.name);
// create a new accessory
const accessory = new this.api.platformAccessory(deviceConfig.name, uuid);
// store a copy of the device object in the `accessory.context`
// the `context` property can be used to store any data about the accessory you may need
accessory.context.device = deviceConfig;
// create the accessory handler for the newly create accessory
// this is imported from `platformAccessory.ts`
new platformAccessory_1.ShadesAccessory(this, accessory, new somaDevice_1.SOMADevice(this.log, peripheral));
// link the accessory to your platform
this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
}
}
}
exports.SOMAShadesPlatform = SOMAShadesPlatform;
//# sourceMappingURL=platform.js.map