mirror of
https://github.com/mtan93/homebridge.git
synced 2026-03-08 05:31:55 +00:00
Init Plugin 2.0
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
This is an example plugin for homebridge. It is a fully-working implementation of a Lockitron door lock accessory.
|
||||
|
||||
Remember to run `npm install` in this directory in order to install the dependencies needed by this plugin. If a user is installing your plugin from npm, this will be done automatically for them.
|
||||
@@ -1,82 +0,0 @@
|
||||
var request = require("request");
|
||||
var Service, Characteristic;
|
||||
|
||||
module.exports = function(homebridge) {
|
||||
Service = homebridge.hap.Service;
|
||||
Characteristic = homebridge.hap.Characteristic;
|
||||
|
||||
homebridge.registerAccessory("homebridge-lockitron", "Lockitron", LockitronAccessory);
|
||||
}
|
||||
|
||||
function LockitronAccessory(log, config) {
|
||||
this.log = log;
|
||||
this.name = config["name"];
|
||||
this.accessToken = config["api_token"];
|
||||
this.lockID = config["lock_id"];
|
||||
|
||||
this.service = new Service.LockMechanism(this.name);
|
||||
|
||||
this.service
|
||||
.getCharacteristic(Characteristic.LockCurrentState)
|
||||
.on('get', this.getState.bind(this));
|
||||
|
||||
this.service
|
||||
.getCharacteristic(Characteristic.LockTargetState)
|
||||
.on('get', this.getState.bind(this))
|
||||
.on('set', this.setState.bind(this));
|
||||
}
|
||||
|
||||
LockitronAccessory.prototype.getState = function(callback) {
|
||||
this.log("Getting current state...");
|
||||
|
||||
request.get({
|
||||
url: "https://api.lockitron.com/v2/locks/"+this.lockID,
|
||||
qs: { access_token: this.accessToken }
|
||||
}, function(err, response, body) {
|
||||
|
||||
if (!err && response.statusCode == 200) {
|
||||
var json = JSON.parse(body);
|
||||
var state = json.state; // "lock" or "unlock"
|
||||
this.log("Lock state is %s", state);
|
||||
var locked = state == "lock"
|
||||
callback(null, locked); // success
|
||||
}
|
||||
else {
|
||||
this.log("Error getting state (status code %s): %s", response.statusCode, err);
|
||||
callback(err);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
LockitronAccessory.prototype.setState = function(state, callback) {
|
||||
var lockitronState = (state == Characteristic.LockTargetState.SECURED) ? "lock" : "unlock";
|
||||
|
||||
this.log("Set state to %s", lockitronState);
|
||||
|
||||
request.put({
|
||||
url: "https://api.lockitron.com/v2/locks/"+this.lockID,
|
||||
qs: { access_token: this.accessToken, state: lockitronState }
|
||||
}, function(err, response, body) {
|
||||
|
||||
if (!err && response.statusCode == 200) {
|
||||
this.log("State change complete.");
|
||||
|
||||
// we succeeded, so update the "current" state as well
|
||||
var currentState = (state == Characteristic.LockTargetState.SECURED) ?
|
||||
Characteristic.LockCurrentState.SECURED : Characteristic.LockCurrentState.UNSECURED;
|
||||
|
||||
this.service
|
||||
.setCharacteristic(Characteristic.LockCurrentState, currentState);
|
||||
|
||||
callback(null); // success
|
||||
}
|
||||
else {
|
||||
this.log("Error '%s' setting lock state. Response: %s", err, body);
|
||||
callback(err || new Error("Error setting lock state."));
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
LockitronAccessory.prototype.getServices = function() {
|
||||
return [this.service];
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "homebridge-lockitron",
|
||||
"version": "0.0.1",
|
||||
"description": "Lockitron plugin for homebridge: https://github.com/nfarina/homebridge",
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"homebridge-plugin"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/example/homebridge-lockitron.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "http://github.com/example/homebridge-lockitron/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.12.0",
|
||||
"homebridge": ">=0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"request": "^2.65.0"
|
||||
}
|
||||
}
|
||||
49
lib/api.js
49
lib/api.js
@@ -1,7 +1,10 @@
|
||||
var inherits = require('util').inherits;
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var hap = require("hap-nodejs");
|
||||
var hapLegacyTypes = require("hap-nodejs/accessories/types.js");
|
||||
var log = require("./logger")._system;
|
||||
var User = require("./user").User;
|
||||
var PlatformAccessory = require("./platformAccessory").PlatformAccessory;
|
||||
|
||||
// The official homebridge API is the object we feed the plugin's exported initializer function.
|
||||
|
||||
@@ -12,7 +15,13 @@ module.exports = {
|
||||
function API() {
|
||||
this._accessories = {}; // this._accessories[pluginName.accessoryName] = accessory constructor
|
||||
this._platforms = {}; // this._platforms[pluginName.platformName] = platform constructor
|
||||
|
||||
this._configurableAccessories = {};
|
||||
this._dynamicPlatforms = {}; // this._dynamicPlatforms[pluginName.platformName] = platform constructor
|
||||
|
||||
// expose the homebridge API version
|
||||
this.version = 2.0;
|
||||
|
||||
// expose the User class methods to plugins to get paths. Example: homebridge.user.storagePath()
|
||||
this.user = User;
|
||||
|
||||
@@ -24,8 +33,12 @@ function API() {
|
||||
// we also need to "bolt on" the legacy "types" constants for older accessories/platforms
|
||||
// still using the "object literal" style JSON.
|
||||
this.hapLegacyTypes = hapLegacyTypes;
|
||||
|
||||
this.platformAccessory = PlatformAccessory;
|
||||
}
|
||||
|
||||
inherits(API, EventEmitter);
|
||||
|
||||
API.prototype.accessory = function(name) {
|
||||
|
||||
// if you passed the "short form" name like "Lockitron" instead of "homebridge-lockitron.Lockitron",
|
||||
@@ -56,7 +69,7 @@ API.prototype.accessory = function(name) {
|
||||
}
|
||||
}
|
||||
|
||||
API.prototype.registerAccessory = function(pluginName, accessoryName, constructor) {
|
||||
API.prototype.registerAccessory = function(pluginName, accessoryName, constructor, configurationRequestHandler) {
|
||||
var fullName = pluginName + "." + accessoryName;
|
||||
|
||||
if (this._accessories[fullName])
|
||||
@@ -65,6 +78,11 @@ API.prototype.registerAccessory = function(pluginName, accessoryName, constructo
|
||||
log.info("Registering accessory '%s'", fullName);
|
||||
|
||||
this._accessories[fullName] = constructor;
|
||||
|
||||
// The plugin supports configuration
|
||||
if (configurationRequestHandler) {
|
||||
this._configurableAccessories[fullName] = configurationRequestHandler;
|
||||
}
|
||||
}
|
||||
|
||||
API.prototype.platform = function(name) {
|
||||
@@ -97,7 +115,7 @@ API.prototype.platform = function(name) {
|
||||
}
|
||||
}
|
||||
|
||||
API.prototype.registerPlatform = function(pluginName, platformName, constructor) {
|
||||
API.prototype.registerPlatform = function(pluginName, platformName, constructor, dynamic) {
|
||||
var fullName = pluginName + "." + platformName;
|
||||
|
||||
if (this._platforms[fullName])
|
||||
@@ -106,4 +124,31 @@ API.prototype.registerPlatform = function(pluginName, platformName, constructor)
|
||||
log.info("Registering platform '%s'", fullName);
|
||||
|
||||
this._platforms[fullName] = constructor;
|
||||
|
||||
if (dynamic) {
|
||||
this._dynamicPlatforms[fullName] = constructor;
|
||||
}
|
||||
}
|
||||
|
||||
API.prototype.registerPlatformAccessories = function(pluginName, platformName, accessories) {
|
||||
for (var index in accessories) {
|
||||
var accessory = accessories[index];
|
||||
if (!(accessory instanceof PlatformAccessory)) {
|
||||
throw new Error(pluginName + " - " + platformName + " attempt to register an accessory that isn\'t PlatformAccessory!");
|
||||
}
|
||||
accessory._associatedPlugin = pluginName;
|
||||
accessory._associatedPlatform = platformName;
|
||||
}
|
||||
|
||||
this.emit('registerPlatformAccessories', accessories);
|
||||
}
|
||||
|
||||
API.prototype.unregisterPlatformAccessories = function(pluginName, platformName, accessories) {
|
||||
for (var index in accessories) {
|
||||
var accessory = accessories[index];
|
||||
if (!(accessory instanceof PlatformAccessory)) {
|
||||
throw new Error(pluginName + " - " + platformName + " attempt to unregister an accessory that isn\'t PlatformAccessory!");
|
||||
}
|
||||
}
|
||||
this.emit('unregisterPlatformAccessories', accessories);
|
||||
}
|
||||
96
lib/bridgeSetupManager.js
Normal file
96
lib/bridgeSetupManager.js
Normal file
@@ -0,0 +1,96 @@
|
||||
var inherits = require('util').inherits;
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var Service = require("hap-nodejs").Service;
|
||||
var Characteristic = require("hap-nodejs").Characteristic;
|
||||
var SetupSession = require("./bridgeSetupSession").SetupSession;
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
BridgeSetupManager: BridgeSetupManager
|
||||
}
|
||||
|
||||
function BridgeSetupManager() {
|
||||
this.session;
|
||||
|
||||
this.service = new Service(null, "49FB9D4D-0FEA-4BF1-8FA6-E7B18AB86DCE");
|
||||
|
||||
this.stateCharacteristic = new Characteristic("State", "77474A2F-FA98-485E-97BE-4762458774D8", {
|
||||
format: Characteristic.Formats.UINT8,
|
||||
minValue: 0,
|
||||
maxValue: 1,
|
||||
minStep: 1,
|
||||
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
|
||||
});
|
||||
this.stateCharacteristic.value = 0;
|
||||
this.service.addCharacteristic(this.stateCharacteristic);
|
||||
|
||||
this.versionCharacteristic = new Characteristic("Version", "FD9FE4CC-D06F-4FFE-96C6-595D464E1026", {
|
||||
format: Characteristic.Formats.STRING,
|
||||
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
|
||||
});
|
||||
this.versionCharacteristic.value = "1.0";
|
||||
this.service.addCharacteristic(this.versionCharacteristic);
|
||||
|
||||
this.controlPointCharacteristic = new Characteristic("Control Point", "5819A4C2-E1B0-4C9D-B761-3EB1AFF43073", {
|
||||
format: Characteristic.Formats.DATA,
|
||||
perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY]
|
||||
})
|
||||
this.controlPointCharacteristic.on('get', function(callback, context) {
|
||||
this.handleReadRequest(callback, context);
|
||||
}.bind(this));
|
||||
this.controlPointCharacteristic.on('set', function(newValue, callback, context) {
|
||||
this.handleWriteRequest(newValue, callback, context);
|
||||
}.bind(this));
|
||||
|
||||
this.controlPointCharacteristic.value = null;
|
||||
this.service.addCharacteristic(this.controlPointCharacteristic);
|
||||
}
|
||||
|
||||
inherits(BridgeSetupManager, EventEmitter);
|
||||
|
||||
BridgeSetupManager.prototype.handleReadRequest = function(callback, context) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.session) {
|
||||
callback(null);
|
||||
} else {
|
||||
this.session.handleReadRequest(callback);
|
||||
}
|
||||
}
|
||||
|
||||
BridgeSetupManager.prototype.handleWriteRequest = function(value, callback, context) {
|
||||
if (!context) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var data = new Buffer(value, 'base64');
|
||||
var request = JSON.parse(data.toString());
|
||||
callback();
|
||||
|
||||
if (!this.session || this.session.sessionUUID !== request.sid) {
|
||||
if (this.session) {
|
||||
this.session.removeAllListeners();
|
||||
this.session.validSession = false;
|
||||
}
|
||||
|
||||
this.session = new SetupSession(this.stateCharacteristic, this.controlPointCharacteristic);
|
||||
this.session.configurablePlatformPlugins = this.configurablePlatformPlugins;
|
||||
this.session.on('newConfig', function(type, name, replace, config) {
|
||||
this.emit('newConfig', type, name, replace, config);
|
||||
}.bind(this));
|
||||
|
||||
this.session.on('requestCurrentConfig', function(callback) {
|
||||
this.emit('requestCurrentConfig', callback);
|
||||
}.bind(this));
|
||||
|
||||
this.session.on('end', function() {
|
||||
this.session = null;
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
this.session.handleWriteRequest(request);
|
||||
}
|
||||
177
lib/bridgeSetupSession.js
Normal file
177
lib/bridgeSetupSession.js
Normal file
File diff suppressed because one or more lines are too long
152
lib/platformAccessory.js
Normal file
152
lib/platformAccessory.js
Normal file
@@ -0,0 +1,152 @@
|
||||
var uuid = require("hap-nodejs").uuid;
|
||||
var Accessory = require("hap-nodejs").Accessory;
|
||||
var Service = require("hap-nodejs").Service;
|
||||
var Characteristic = require("hap-nodejs").Characteristic;
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
PlatformAccessory: PlatformAccessory
|
||||
}
|
||||
|
||||
function PlatformAccessory(displayName, UUID, category) {
|
||||
if (!displayName) throw new Error("Accessories must be created with a non-empty displayName.");
|
||||
if (!UUID) throw new Error("Accessories must be created with a valid UUID.");
|
||||
if (!uuid.isValid(UUID)) throw new Error("UUID '" + UUID + "' is not a valid UUID. Try using the provided 'generateUUID' function to create a valid UUID from any arbitrary string, like a serial number.");
|
||||
|
||||
this.displayName = displayName;
|
||||
this.UUID = UUID;
|
||||
this.category = category || Accessory.Categories.OTHER;
|
||||
this.services = [];
|
||||
this.reachable = false;
|
||||
this.context = {};
|
||||
|
||||
this._associatedPlugin;
|
||||
this._associatedPlatform;
|
||||
this._associatedHAPAccessory;
|
||||
|
||||
this
|
||||
.addService(Service.AccessoryInformation)
|
||||
.setCharacteristic(Characteristic.Name, displayName)
|
||||
.setCharacteristic(Characteristic.Manufacturer, "Default-Manufacturer")
|
||||
.setCharacteristic(Characteristic.Model, "Default-Model")
|
||||
.setCharacteristic(Characteristic.SerialNumber, "Default-SerialNumber");
|
||||
}
|
||||
|
||||
PlatformAccessory.prototype.addService = function(service) {
|
||||
// service might be a constructor like `Service.AccessoryInformation` instead of an instance
|
||||
// of Service. Coerce if necessary.
|
||||
if (typeof service === 'function')
|
||||
service = new (Function.prototype.bind.apply(service, arguments));
|
||||
|
||||
// check for UUID+subtype conflict
|
||||
for (var index in this.services) {
|
||||
var existing = this.services[index];
|
||||
if (existing.UUID === service.UUID) {
|
||||
// OK we have two Services with the same UUID. Check that each defines a `subtype` property and that each is unique.
|
||||
if (!service.subtype)
|
||||
throw new Error("Cannot add a Service with the same UUID '" + existing.UUID + "' as another Service in this Accessory without also defining a unique 'subtype' property.");
|
||||
|
||||
if (service.subtype.toString() === existing.subtype.toString())
|
||||
throw new Error("Cannot add a Service with the same UUID '" + existing.UUID + "' and subtype '" + existing.subtype + "' as another Service in this Accessory.");
|
||||
}
|
||||
}
|
||||
|
||||
this.services.push(service);
|
||||
|
||||
if (this._associatedHAPAccessory) {
|
||||
this._associatedHAPAccessory.addService(service);
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
PlatformAccessory.prototype.getService = function(name) {
|
||||
for (var index in this.services) {
|
||||
var service = this.services[index];
|
||||
|
||||
if (typeof name === 'string' && (service.displayName === name || service.name === name))
|
||||
return service;
|
||||
else if (typeof name === 'function' && ((service instanceof name) || (name.UUID === service.UUID)))
|
||||
return service;
|
||||
}
|
||||
}
|
||||
|
||||
PlatformAccessory.prototype.updateReachability = function(reachable) {
|
||||
this.reachable = reachable;
|
||||
|
||||
if (this._associatedHAPAccessory) {
|
||||
this._associatedHAPAccessory.updateReachability(reachable);
|
||||
}
|
||||
}
|
||||
|
||||
PlatformAccessory.prototype._prepareAssociatedHAPAccessory = function () {
|
||||
this._associatedHAPAccessory = new Accessory(this.displayName, this.UUID);
|
||||
this._associatedHAPAccessory._sideloadServices(this.services);
|
||||
this._associatedHAPAccessory.reachable = this.reachable;
|
||||
}
|
||||
|
||||
PlatformAccessory.prototype._dictionaryPresentation = function() {
|
||||
var accessory = {};
|
||||
|
||||
accessory.plugin = this._associatedPlugin;
|
||||
accessory.platform = this._associatedPlatform;
|
||||
accessory.displayName = this.displayName;
|
||||
accessory.UUID = this.UUID;
|
||||
accessory.category = this.category;
|
||||
accessory.context = this.context;
|
||||
|
||||
var services = [];
|
||||
for (var index in this.services) {
|
||||
var service = this.services[index];
|
||||
var servicePresentation = {};
|
||||
servicePresentation.displayName = service.displayName;
|
||||
servicePresentation.UUID = service.UUID;
|
||||
servicePresentation.subtype = service.subtype;
|
||||
|
||||
var characteristics = [];
|
||||
for (var cIndex in service.characteristics) {
|
||||
var characteristic = service.characteristics[cIndex];
|
||||
var characteristicPresentation = {};
|
||||
characteristicPresentation.displayName = characteristic.displayName;
|
||||
characteristicPresentation.UUID = characteristic.UUID;
|
||||
characteristicPresentation.props = characteristic.props;
|
||||
characteristicPresentation.value = characteristic.value;
|
||||
characteristics.push(characteristicPresentation);
|
||||
}
|
||||
|
||||
servicePresentation.characteristics = characteristics;
|
||||
services.push(servicePresentation);
|
||||
}
|
||||
|
||||
accessory.services = services;
|
||||
return accessory;
|
||||
}
|
||||
|
||||
PlatformAccessory.prototype._configFromData = function(data) {
|
||||
this._associatedPlugin = data.plugin;
|
||||
this._associatedPlatform = data.platform;
|
||||
this.displayName = data.displayName;
|
||||
this.UUID = data.UUID;
|
||||
this.category = data.category;
|
||||
this.context = data.context;
|
||||
this.reachable = false;
|
||||
|
||||
var services = [];
|
||||
for (var index in data.services) {
|
||||
var service = data.services[index];
|
||||
var hapService = new Service(service.displayName, service.UUID, service.subtype);
|
||||
|
||||
var characteristics = [];
|
||||
for (var cIndex in service.characteristics) {
|
||||
var characteristic = service.characteristics[cIndex];
|
||||
var hapCharacteristic = new Characteristic(characteristic.displayName, characteristic.UUID, characteristic.props);
|
||||
hapCharacteristic.value = characteristic.value;
|
||||
characteristics.push(hapCharacteristic);
|
||||
}
|
||||
|
||||
hapService._sideloadCharacteristics(characteristics);
|
||||
services.push(hapService);
|
||||
}
|
||||
|
||||
this.services = services;
|
||||
}
|
||||
243
lib/server.js
243
lib/server.js
@@ -1,6 +1,7 @@
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var uuid = require("hap-nodejs").uuid;
|
||||
var accessoryStorage = require('node-persist').create();
|
||||
var Bridge = require("hap-nodejs").Bridge;
|
||||
var Accessory = require("hap-nodejs").Accessory;
|
||||
var Service = require("hap-nodejs").Service;
|
||||
@@ -10,6 +11,8 @@ var once = require("hap-nodejs/lib/util/once").once;
|
||||
var Plugin = require('./plugin').Plugin;
|
||||
var User = require('./user').User;
|
||||
var API = require('./api').API;
|
||||
var PlatformAccessory = require("./platformAccessory").PlatformAccessory;
|
||||
var BridgeSetupManager = require("./bridgeSetupManager").BridgeSetupManager;
|
||||
var log = require("./logger")._system;
|
||||
var Logger = require('./logger').Logger;
|
||||
|
||||
@@ -20,10 +23,32 @@ module.exports = {
|
||||
}
|
||||
|
||||
function Server() {
|
||||
// Setup Accessory Cache Storage
|
||||
accessoryStorage.initSync({ dir: User.cachedAccessoryPath() });
|
||||
|
||||
this._api = new API(); // object we feed to Plugins
|
||||
|
||||
this._api.on('registerPlatformAccessories', function(accessories) {
|
||||
this._handleRegisterPlatformAccessories(accessories);
|
||||
}.bind(this));
|
||||
|
||||
this._api.on('unregisterPlatformAccessories', function(accessories) {
|
||||
this._handleUnregisterPlatformAccessories(accessories);
|
||||
}.bind(this));
|
||||
|
||||
this._plugins = this._loadPlugins(); // plugins[name] = Plugin instance
|
||||
this._config = this._loadConfig();
|
||||
this._config = this._loadConfig();
|
||||
this._cachedPlatformAccessories = this._loadCachedPlatformAccessories();
|
||||
this._bridge = this._createBridge();
|
||||
|
||||
this._activeDynamicPlugins = {};
|
||||
this._configurablePlatformPlugins = {};
|
||||
this._setupManager = new BridgeSetupManager();
|
||||
this._setupManager.on('newConfig', this._handleNewConfig.bind(this));
|
||||
|
||||
this._setupManager.on('requestCurrentConfig', function(callback) {
|
||||
callback(this._config);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
Server.prototype.run = function() {
|
||||
@@ -34,12 +59,18 @@ Server.prototype.run = function() {
|
||||
|
||||
if (this._config.platforms) this._loadPlatforms();
|
||||
if (this._config.accessories) this._loadAccessories();
|
||||
this._loadDynamicPlatforms();
|
||||
this._configCachedPlatformAccessories();
|
||||
this._setupManager.configurablePlatformPlugins = this._configurablePlatformPlugins;
|
||||
this._bridge.addService(this._setupManager.service);
|
||||
|
||||
this._asyncWait = false;
|
||||
|
||||
// publish now unless we're waiting on anyone
|
||||
if (this._asyncCalls == 0)
|
||||
this._publish();
|
||||
|
||||
this._api.emit('didFinishLaunching');
|
||||
}
|
||||
|
||||
Server.prototype._publish = function() {
|
||||
@@ -108,8 +139,18 @@ Server.prototype._loadConfig = function() {
|
||||
|
||||
// Complain and exit if it doesn't exist yet
|
||||
if (!fs.existsSync(configPath)) {
|
||||
log.error("Couldn't find a config.json file at '"+configPath+"'. Look at config-sample.json for examples of how to format your config.js and add your home accessories.");
|
||||
process.exit(1);
|
||||
var config = {};
|
||||
|
||||
config.bridge = {
|
||||
"name": "Homebridge",
|
||||
"username": "CC:22:3D:E3:CE:30",
|
||||
"port": 51826,
|
||||
"pin": "031-45-154"
|
||||
};
|
||||
|
||||
return config;
|
||||
// log.error("Couldn't find a config.json file at '"+configPath+"'. Look at config-sample.json for examples of how to format your config.js and add your home accessories.");
|
||||
// process.exit(1);
|
||||
}
|
||||
|
||||
// Load up the configuration file
|
||||
@@ -142,6 +183,23 @@ Server.prototype._loadConfig = function() {
|
||||
return config;
|
||||
}
|
||||
|
||||
Server.prototype._loadCachedPlatformAccessories = function() {
|
||||
var cachedAccessories = accessoryStorage.getItem("cachedAccessories");
|
||||
var platformAccessories = [];
|
||||
|
||||
if (cachedAccessories) {
|
||||
for (var index in cachedAccessories) {
|
||||
var serializedAccessory = cachedAccessories[index];
|
||||
var platformAccessory = new PlatformAccessory(serializedAccessory.displayName, serializedAccessory.UUID, serializedAccessory.category);
|
||||
platformAccessory._configFromData(serializedAccessory);
|
||||
|
||||
platformAccessories.push(platformAccessory);
|
||||
}
|
||||
}
|
||||
|
||||
return platformAccessories;
|
||||
}
|
||||
|
||||
Server.prototype._createBridge = function() {
|
||||
// pull out our custom Bridge settings from config.json, if any
|
||||
var bridgeConfig = this._config.bridge || {};
|
||||
@@ -201,11 +259,64 @@ Server.prototype._loadPlatforms = function() {
|
||||
|
||||
platformLogger("Initializing %s platform...", platformType);
|
||||
|
||||
var platformInstance = new platformConstructor(platformLogger, platformConfig);
|
||||
this._loadPlatformAccessories(platformInstance, platformLogger, platformType);
|
||||
var platformInstance = new platformConstructor(platformLogger, platformConfig, this._api);
|
||||
|
||||
if (platformInstance.configureAccessory == undefined) {
|
||||
// Plugin 1.0, load accessories
|
||||
this._loadPlatformAccessories(platformInstance, platformLogger, platformType);
|
||||
} else {
|
||||
this._activeDynamicPlugins[platformType] = platformInstance;
|
||||
}
|
||||
|
||||
if (platformInstance.configurationRequestHandler != undefined) {
|
||||
this._configurablePlatformPlugins[platformType] = platformInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Server.prototype._loadDynamicPlatforms = function() {
|
||||
for (var dynamicPluginName in this._api._dynamicPlatforms) {
|
||||
if (!this._activeDynamicPlugins[dynamicPluginName] && !this._activeDynamicPlugins[dynamicPluginName.split(".")[1]]) {
|
||||
console.log("Load " + dynamicPluginName);
|
||||
var platformConstructor = this._api._dynamicPlatforms[dynamicPluginName];
|
||||
var platformLogger = Logger.withPrefix(dynamicPluginName);
|
||||
var platformInstance = new platformConstructor(platformLogger, null, this._api);
|
||||
this._activeDynamicPlugins[dynamicPluginName] = platformInstance;
|
||||
|
||||
if (platformInstance.configurationRequestHandler != undefined) {
|
||||
this._configurablePlatformPlugins[dynamicPluginName] = platformInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Server.prototype._configCachedPlatformAccessories = function() {
|
||||
for (var index in this._cachedPlatformAccessories) {
|
||||
var accessory = this._cachedPlatformAccessories[index];
|
||||
|
||||
if (!(accessory instanceof PlatformAccessory)) {
|
||||
console.log("Unexpected Accessory!");
|
||||
continue;
|
||||
}
|
||||
|
||||
var fullName = accessory._associatedPlugin + "." + accessory._associatedPlatform;
|
||||
var platformInstance = this._activeDynamicPlugins[fullName];
|
||||
|
||||
if (!platformInstance) {
|
||||
platformInstance = this._activeDynamicPlugins[accessory._associatedPlatform];
|
||||
}
|
||||
|
||||
if (platformInstance) {
|
||||
platformInstance.configureAccessory(accessory);
|
||||
} else {
|
||||
console.log("Failed to find plugin to handle accessory " + accessory.displayName);
|
||||
}
|
||||
|
||||
accessory._prepareAssociatedHAPAccessory();
|
||||
this._bridge.addBridgedAccessory(accessory._associatedHAPAccessory);
|
||||
}
|
||||
}
|
||||
|
||||
Server.prototype._loadPlatformAccessories = function(platformInstance, log, platformType) {
|
||||
this._asyncCalls++;
|
||||
platformInstance.accessories(once(function(foundAccessories){
|
||||
@@ -280,6 +391,128 @@ Server.prototype._createAccessory = function(accessoryInstance, displayName, acc
|
||||
}
|
||||
}
|
||||
|
||||
Server.prototype._handleRegisterPlatformAccessories = function(accessories) {
|
||||
var hapAccessories = [];
|
||||
for (var index in accessories) {
|
||||
var accessory = accessories[index];
|
||||
|
||||
accessory._prepareAssociatedHAPAccessory();
|
||||
hapAccessories.push(accessory._associatedHAPAccessory);
|
||||
|
||||
this._cachedPlatformAccessories.push(accessory);
|
||||
}
|
||||
|
||||
this._bridge.addBridgedAccessories(hapAccessories);
|
||||
this._updateCachedAccessories();
|
||||
}
|
||||
|
||||
Server.prototype._handleUnregisterPlatformAccessories = function(accessories) {
|
||||
var hapAccessories = [];
|
||||
for (var index in accessories) {
|
||||
var accessory = accessories[index];
|
||||
|
||||
if (accessory._associatedHAPAccessory) {
|
||||
hapAccessories.push(accessory._associatedHAPAccessory);
|
||||
}
|
||||
|
||||
for (var targetIndex in this._cachedPlatformAccessories) {
|
||||
var existing = this._cachedPlatformAccessories[targetIndex];
|
||||
if (existing.UUID === accessory.UUID) {
|
||||
this._cachedPlatformAccessories.splice(targetIndex, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._bridge.removeBridgedAccessories(hapAccessories);
|
||||
this._updateCachedAccessories();
|
||||
}
|
||||
|
||||
Server.prototype._updateCachedAccessories = function() {
|
||||
var serializedAccessories = [];
|
||||
|
||||
for (var index in this._cachedPlatformAccessories) {
|
||||
var accessory = this._cachedPlatformAccessories[index];
|
||||
serializedAccessories.push(accessory._dictionaryPresentation());
|
||||
}
|
||||
|
||||
accessoryStorage.setItemSync("cachedAccessories", serializedAccessories);
|
||||
}
|
||||
|
||||
Server.prototype._handleNewConfig = function(type, name, replace, config) {
|
||||
if (type === "accessory") {
|
||||
// TODO: Load new accessory
|
||||
if (!this._config.accessories) {
|
||||
this._config.accessories = [];
|
||||
}
|
||||
|
||||
if (!replace) {
|
||||
this._config.accessories.push(config);
|
||||
} else {
|
||||
var targetName;
|
||||
if (name.indexOf('.') == -1) {
|
||||
targetName = name.split(".")[1];
|
||||
}
|
||||
var found = false;
|
||||
for (var index in this._config.accessories) {
|
||||
var accessoryConfig = this._config.accessories[index];
|
||||
if (accessoryConfig.accessory === name) {
|
||||
this._config.accessories[index] = config;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (targetName && (accessoryConfig.accessory === targetName)) {
|
||||
this._config.accessories[index] = config;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
this._config.accessories.push(config);
|
||||
}
|
||||
}
|
||||
} else if (type === "platform") {
|
||||
if (!this._config.platforms) {
|
||||
this._config.platforms = [];
|
||||
}
|
||||
|
||||
if (!replace) {
|
||||
this._config.platforms.push(config);
|
||||
} else {
|
||||
var targetName;
|
||||
if (name.indexOf('.') == -1) {
|
||||
targetName = name.split(".")[1];
|
||||
}
|
||||
|
||||
var found = false;
|
||||
for (var index in this._config.platforms) {
|
||||
var platformConfig = this._config.platforms[index];
|
||||
if (platformConfig.platform === name) {
|
||||
this._config.platforms[index] = config;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (targetName && (platformConfig.platform === targetName)) {
|
||||
this._config.platforms[index] = config;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
this._config.platforms.push(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var serializedConfig = JSON.stringify(this._config, null, ' ');
|
||||
var configPath = User.configPath();
|
||||
fs.writeFileSync(configPath, serializedConfig, 'utf8');
|
||||
}
|
||||
|
||||
// Returns the setup code in a scannable format.
|
||||
Server.prototype._printPin = function(pin) {
|
||||
console.log("Scan this code with your HomeKit App on your iOS device to pair with Homebridge:");
|
||||
|
||||
@@ -38,6 +38,10 @@ User.persistPath = function() {
|
||||
return path.join(User.storagePath(), "persist");
|
||||
}
|
||||
|
||||
User.cachedAccessoryPath = function() {
|
||||
return path.join(User.storagePath(), "accessories");
|
||||
}
|
||||
|
||||
User.setStoragePath = function(path) {
|
||||
customStoragePath = path;
|
||||
}
|
||||
@@ -31,7 +31,8 @@
|
||||
"dependencies": {
|
||||
"chalk": "^1.1.1",
|
||||
"commander": "2.8.1",
|
||||
"hap-nodejs": "0.1.1",
|
||||
"semver": "5.0.3"
|
||||
"hap-nodejs": "0.1.6",
|
||||
"semver": "5.0.3",
|
||||
"node-persist": "^0.0.8"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user