homebridge-http-webhooks-plus 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ # Migrating to HTTP Webhooks Plus 0.2.1
2
+
3
+ This release republishes the upstream 0.2.0 implementation under the independent
4
+ package name `homebridge-http-webhooks-plus`. All `src/` files, the configuration
5
+ schema, runtime dependencies and declared runtime requirements are unchanged.
6
+ The package name passed to Homebridge registration is updated; the platform and
7
+ accessory aliases are preserved. No new state modes or feedback API ship in 0.2.1.
8
+
9
+ ## Existing HomeKit accessories
10
+
11
+ Keep the existing `"platform": "HttpWebHooks"` configuration and every configured
12
+ accessory ID and name. Preserve the existing main/child bridge username, pairing,
13
+ port, persistent storage, service types and accessory configuration. Do not remove
14
+ the bridge or accessories in Apple Home, recreate the platform, clear cached
15
+ accessories or reset pairing as part of this package replacement.
16
+
17
+ Homebridge's static-platform UUID construction uses the configured platform
18
+ identifier and the accessory UUID base/name. With the existing unqualified
19
+ `HttpWebHooks` identifier and unchanged configuration, this release preserves
20
+ those inputs and the complete accessory implementation. Package-registration
21
+ tests and exact upstream runtime fingerprints protect this release boundary.
22
+ The owner's actual HomeKit rooms, scenes and automations still need checking
23
+ after a backed-up migration; source checks cannot verify a particular Home.
24
+
25
+ A package-qualified identifier such as
26
+ `homebridge-http-webhooks.HttpWebHooks` needs a separately reviewed migration:
27
+ changing its prefix can change the UUID seed. The same caution applies to
28
+ package-qualified standalone accessory identifiers. Do not blindly replace
29
+ every occurrence of the old package name in configuration or persistent data.
30
+
31
+ ## Package replacement
32
+
33
+ 1. Record the installed version and location, Node/Homebridge versions and any
34
+ locally modified source files. Make a private backup of the package, full
35
+ Homebridge configuration, persistent storage and pairing data.
36
+ 2. Stop integrations that issue commands or publish state, then stop Homebridge
37
+ using the service manager appropriate to your installation.
38
+ 3. Replace the old package with the pinned Plus version in the same Homebridge
39
+ plugin installation location. Do not load both packages together: their
40
+ platform and accessory aliases intentionally overlap.
41
+ 4. If top-level plugin allowlists or disabled-plugin lists are used, migrate
42
+ the package entry deliberately. Retain the platform/accessory configuration
43
+ and bridge identity. Check external tools for saved package paths or integrity
44
+ receipts before restarting them.
45
+ 5. Start Homebridge, verify the loaded package, and check that all existing
46
+ accessories remain in the same rooms and automations. Then resume dependent
47
+ integrations after their read-only readiness checks pass.
48
+
49
+ Installation directories vary between system packages, containers, global npm
50
+ and development setups. Use the existing Homebridge installation method; a
51
+ global npm command in an unrelated Node installation can affect the wrong copy.
52
+
53
+ ## Locally patched installations
54
+
55
+ The public npm artifact contains generic upstream behavior. A locally patched
56
+ installation needs its patches preserved separately during this first migration.
57
+ Compare the exact original files and patched files, retain the installed hashes
58
+ and backups, and adapt any deployment receipts or saved paths. Do not assume
59
+ ordinary reinstalling retains changes made inside `node_modules`.
60
+
61
+ The package has no dependency on any particular controller or deployment script.
62
+ Future configurable features will allow integrations to stop patching installed
63
+ source. Integration-specific migration logic belongs to those integrations.
64
+
65
+ ## State behavior retained from upstream
66
+
67
+ `targetdoorstate` represents the requested final door state; `currentdoorstate`
68
+ represents the reported state. Setting either through a webhook is a state update.
69
+ An existing HomeKit command handler can also optimistically publish final state
70
+ when its outgoing HTTP command succeeds. This first release preserves that
71
+ behavior, including existing limitations; HTTP acceptance does not prove physical
72
+ completion. Garage obstruction reporting is a separate characteristic and is
73
+ not a lock feature. See the README for the existing webhook fields.
package/index.js ADDED
@@ -0,0 +1,35 @@
1
+ var HttpWebHooksPlatform = require('./src/homekit/HttpWebHooksPlatform');
2
+ var HttpWebHookSensorAccessory = require('./src/homekit/accessories/HttpWebHookSensorAccessory');
3
+ var HttpWebHookSwitchAccessory = require('./src/homekit/accessories/HttpWebHookSwitchAccessory');
4
+ var HttpWebHookPushButtonAccessory = require('./src/homekit/accessories/HttpWebHookPushButtonAccessory');
5
+ var HttpWebHookDoorbellAccessory = require('./src/homekit/accessories/HttpWebHookDoorbellAccessory');
6
+ var HttpWebHookLightBulbAccessory = require('./src/homekit/accessories/HttpWebHookLightBulbAccessory');
7
+ var HttpWebHookThermostatAccessory = require('./src/homekit/accessories/HttpWebHookThermostatAccessory');
8
+ var HttpWebHookOutletAccessory = require('./src/homekit/accessories/HttpWebHookOutletAccessory');
9
+ var HttpWebHookSecurityAccessory = require('./src/homekit/accessories/HttpWebHookSecurityAccessory');
10
+ var HttpWebHookGarageDoorOpenerAccessory = require('./src/homekit/accessories/HttpWebHookGarageDoorOpenerAccessory');
11
+ var HttpWebHookStatelessSwitchAccessory = require('./src/homekit/accessories/HttpWebHookStatelessSwitchAccessory');
12
+ var HttpWebHookLockMechanismAccessory = require('./src/homekit/accessories/HttpWebHookLockMechanismAccessory');
13
+ var HttpWebHookWindowCoveringAccessory = require('./src/homekit/accessories/HttpWebHookWindowCoveringAccessory');
14
+ var HttpWebHookFanv2Accessory = require('./src/homekit/accessories/HttpWebHookFanv2Accessory');
15
+ var HttpWebHookCarbonDioxideSensoryAccessory = require('./src/homekit/accessories/HttpWebHookCarbonDioxideSensorAccessory');
16
+ var HttpWebHookValveAccessory = require('./src/homekit/accessories/HttpWebHookValveAccessory');
17
+
18
+ module.exports = function(homebridge) {
19
+ homebridge.registerPlatform("homebridge-http-webhooks-plus", "HttpWebHooks", HttpWebHooksPlatform);
20
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookSensor", HttpWebHookSensorAccessory);
21
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookSwitch", HttpWebHookSwitchAccessory);
22
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookPushButton", HttpWebHookPushButtonAccessory);
23
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookDoorbell", HttpWebHookDoorbellAccessory);
24
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookLight", HttpWebHookLightBulbAccessory);
25
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookThermostat", HttpWebHookThermostatAccessory);
26
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookOutlet", HttpWebHookOutletAccessory);
27
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookSecurity", HttpWebHookSecurityAccessory);
28
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookGarageDoorOpener", HttpWebHookGarageDoorOpenerAccessory);
29
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookStatelessSwitch", HttpWebHookStatelessSwitchAccessory);
30
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookLockMechanism", HttpWebHookLockMechanismAccessory);
31
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookWindowCovering", HttpWebHookWindowCoveringAccessory);
32
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookFanv2", HttpWebHookFanv2Accessory);
33
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookCarbonDioxideSensor", HttpWebHookCarbonDioxideSensoryAccessory);
34
+ homebridge.registerAccessory("homebridge-http-webhooks-plus", "HttpWebHookValve", HttpWebHookValveAccessory);
35
+ };
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "homebridge-http-webhooks-plus",
3
+ "version": "0.2.1",
4
+ "displayName": "Homebridge HTTP Webhooks Plus",
5
+ "description": "HTTP webhooks and virtual accessories for Homebridge; independently maintained fork of homebridge-http-webhooks.",
6
+ "license": "GPL-3.0",
7
+ "keywords": [
8
+ "homebridge-plugin",
9
+ "homebridge",
10
+ "plugin",
11
+ "http",
12
+ "webhook",
13
+ "httpwebhooks",
14
+ "http-webhooks",
15
+ "http webhooks",
16
+ "smart",
17
+ "homekit",
18
+ "siri"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/pponce/homebridge-http-webhooks-plus.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/pponce/homebridge-http-webhooks-plus/issues"
26
+ },
27
+ "engines": {
28
+ "node": ">=9.11.2",
29
+ "homebridge": "^1.8.4||^2.0.0-beta"
30
+ },
31
+ "dependencies": {
32
+ "http-auth": "^4.2.0",
33
+ "node-persist": "^2.1.0",
34
+ "request": "^2.88.2",
35
+ "selfsigned": "^2.4.1"
36
+ },
37
+ "homepage": "https://github.com/pponce/homebridge-http-webhooks-plus#readme",
38
+ "author": "benzman81",
39
+ "files": [
40
+ "index.js",
41
+ "src/",
42
+ "config.schema.json",
43
+ "README.md",
44
+ "CHANGELOG.md",
45
+ "LICENSE",
46
+ "docs/COMPATIBILITY.md"
47
+ ],
48
+ "scripts": {
49
+ "test": "node --test test/*.test.cjs",
50
+ "prepublishOnly": "npm test"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public",
54
+ "registry": "https://registry.npmjs.org/"
55
+ }
56
+ }
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+ DEFAULT_REQUEST_TIMEOUT : 10000,
3
+ DEFAULT_PORT : 51828,
4
+ DEFAULT_SENSOR_TIMEOUT : 5000,
5
+ DEFAULT_CACHE_DIR : "./.node-persist/storage",
6
+ DEFAULT_LISTEN_HOST : "0.0.0.0",
7
+ COVERS_REQUEST_TIMEOUT : 35000,
8
+ CONTEXT_FROM_WEBHOOK : "fromHTTPWebhooks",
9
+ CONTEXT_FROM_TIMEOUTCALL : "fromTimeoutCall",
10
+ CERT_VERSION : 2,
11
+ CERT_DAYS : 365
12
+ };
package/src/Server.js ADDED
@@ -0,0 +1,192 @@
1
+ const Constants = require('./Constants');
2
+
3
+ var request = require("request");
4
+ var http = require('http');
5
+ var https = require('https');
6
+ var url = require('url');
7
+ var auth = require('http-auth');
8
+ var fs = require('fs');
9
+ var Service, Characteristic;
10
+
11
+ function Server(ServiceParam, CharacteristicParam, platform, platformConfig) {
12
+ Service = ServiceParam;
13
+ Characteristic = CharacteristicParam;
14
+
15
+ this.platform = platform;
16
+ this.log = platform.log;
17
+ this.storage = platform.storage;
18
+
19
+ this.webhookPort = platformConfig["webhook_port"] || Constants.DEFAULT_PORT;
20
+ this.webhookListenHost = platformConfig["webhook_listen_host"] || Constants.DEFAULT_LISTEN_HOST;
21
+ this.webhookEnableCORS = platformConfig["webhook_enable_cors"] || false;
22
+ this.httpAuthUser = platformConfig["http_auth_user"] || null;
23
+ this.httpAuthPass = platformConfig["http_auth_pass"] || null;
24
+ this.https = platformConfig["https"] === true;
25
+ this.httpsKeyFile = platformConfig["https_keyfile"];
26
+ this.httpsCertFile = platformConfig["https_certfile"];
27
+ }
28
+
29
+ Server.prototype.setAccessories = function(accessories) {
30
+ this.accessories = accessories;
31
+ };
32
+
33
+ Server.prototype.createSSLCertificate = function() {
34
+ this.log("Generating new ssl certificate.");
35
+ var selfsigned = require('selfsigned');
36
+ var certAttrs = [{ name: 'homebridgeHttpWebhooks', value: 'homebridgeHttpWebhooks.com' , type: 'homebridgeHttpWebhooks'}];
37
+ var certOpts = { days: Constants.CERT_DAYS};
38
+ certOpts.extensions = [{
39
+ name: 'subjectAltName',
40
+ altNames: [{
41
+ type: 2,
42
+ value: 'homebridgeHttpWebhooks.com'
43
+ }, {
44
+ type: 2,
45
+ value: 'localhost'
46
+ }]
47
+ }];
48
+ var pems = selfsigned.generate(certAttrs, certOpts);
49
+ var cachedSSLCert = pems;
50
+ cachedSSLCert.timestamp = Date.now();
51
+ cachedSSLCert.certVersion = Constants.CERT_VERSION;
52
+ return cachedSSLCert;
53
+ };
54
+
55
+ Server.prototype.getSSLServerOptions = function() {
56
+ var sslServerOptions = {};
57
+ if(this.https) {
58
+ if(!this.httpsKeyFile || !this.httpsCertFile) {
59
+ this.log("Using automatic created ssl certificate.");
60
+ var cachedSSLCert = this.storage.getItemSync("http-webhook-ssl-cert");
61
+ if(cachedSSLCert) {
62
+ var certVersion = cachedSSLCert.certVersion;
63
+ var timestamp = Date.now() - cachedSSLCert.timestamp;
64
+ var diffInDays = timestamp/1000/60/60/24;
65
+ if(diffInDays > Constants.CERT_DAYS - 1 || certVersion !== Constants.CERT_VERSION) {
66
+ cachedSSLCert = null;
67
+ }
68
+ }
69
+ if(!cachedSSLCert) {
70
+ cachedSSLCert = this.createSSLCertificate();
71
+ this.storage.setItemSync("http-webhook-ssl-cert", cachedSSLCert);
72
+ }
73
+
74
+ sslServerOptions = {
75
+ key: cachedSSLCert.private,
76
+ cert: cachedSSLCert.cert
77
+ };
78
+ }
79
+ else {
80
+ sslServerOptions = {
81
+ key: fs.readFileSync(this.httpsKeyFile),
82
+ cert: fs.readFileSync(this.httpsCertFile)
83
+ };
84
+ }
85
+ }
86
+ return sslServerOptions;
87
+ };
88
+
89
+ Server.prototype.createServerCallback = function() {
90
+ return (function(request, response) {
91
+ if(this.webhookEnableCORS) {
92
+ // Based on https://gist.github.com/balupton/3696140
93
+ response.setHeader('Access-Control-Allow-Origin', '*');
94
+ response.setHeader('Access-Control-Request-Method', '*');
95
+ response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST');
96
+ response.setHeader('Access-Control-Allow-Headers', '*');
97
+ if (request.method === 'OPTIONS') {
98
+ response.writeHead(200);
99
+ response.end();
100
+ return;
101
+ }
102
+ }
103
+ var theUrl = request.url;
104
+ var theUrlParts = url.parse(theUrl, true);
105
+ var theUrlParams = theUrlParts.query;
106
+ var body = [];
107
+ request.on('error', (function(err) {
108
+ this.log("[ERROR Http WebHook Server] Reason: %s.", err);
109
+ }).bind(this)).on('data', function(chunk) {
110
+ body.push(chunk);
111
+ }).on('end', (function() {
112
+ body = Buffer.concat(body).toString();
113
+
114
+ response.on('error', function(err) {
115
+ this.log("[ERROR Http WebHook Server] Reason: %s.", err);
116
+ });
117
+
118
+ response.statusCode = 200;
119
+ response.setHeader('Content-Type', 'application/json');
120
+
121
+ if (!theUrlParams.accessoryId) {
122
+ response.statusCode = 404;
123
+ response.setHeader("Content-Type", "text/plain");
124
+ var errorText = "[ERROR Http WebHook Server] No accessoryId in request.";
125
+ this.log(errorText);
126
+ response.write(errorText);
127
+ response.end();
128
+ }
129
+ else {
130
+ var responseBody = null;
131
+ var accessoryId = theUrlParams.accessoryId;
132
+ var found = false;
133
+ for (var i = 0; i < this.accessories.length; i++) {
134
+ var accessory = this.accessories[i];
135
+ if (accessory.id === accessoryId) {
136
+ responseBody = accessory.changeFromServer(theUrlParams);
137
+ found = true;
138
+ break;
139
+ }
140
+ }
141
+ if(responseBody) {
142
+ response.write(JSON.stringify(responseBody));
143
+ response.end();
144
+ }
145
+ else {
146
+ response.statusCode = 404;
147
+ response.setHeader("Content-Type", "text/plain");
148
+ var errorText = "[ERROR Http WebHook Server] AccessoryId '"+theUrlParams.accessoryId+"' did not return a response body from 'changeFromServer'.";
149
+ if(!found) {
150
+ errorText = "[ERROR Http WebHook Server] AccessoryId '"+theUrlParams.accessoryId+"' not found.";
151
+ }
152
+ this.log(errorText);
153
+ response.write(errorText);
154
+ response.end();
155
+ }
156
+ }
157
+ }).bind(this));
158
+ }).bind(this);
159
+ };
160
+
161
+ Server.prototype.start = function() {
162
+ var sslServerOptions = this.getSSLServerOptions();
163
+
164
+ var serverCallback = this.createServerCallback();
165
+
166
+ if (this.httpAuthUser && this.httpAuthPass) {
167
+ var httpAuthUser = this.httpAuthUser;
168
+ var httpAuthPass = this.httpAuthPass;
169
+ basicAuth = auth.basic({
170
+ realm : "Auth required"
171
+ }, function(username, password, callback) {
172
+ callback(username === httpAuthUser && password === httpAuthPass);
173
+ });
174
+ if(this.https) {
175
+ https.createServer(basicAuth, sslServerOptions, serverCallback).listen(this.webhookPort, this.webhookListenHost);
176
+ }
177
+ else {
178
+ http.createServer(basicAuth, serverCallback).listen(this.webhookPort, this.webhookListenHost);
179
+ }
180
+ }
181
+ else {
182
+ if(this.https) {
183
+ https.createServer(sslServerOptions, serverCallback).listen(this.webhookPort, this.webhookListenHost);
184
+ }
185
+ else {
186
+ http.createServer(serverCallback).listen(this.webhookPort, this.webhookListenHost);
187
+ }
188
+ }
189
+ this.log("Started server for webhooks on port '%s' listening for host '%s'.", this.webhookPort, this.webhookListenHost);
190
+ };
191
+
192
+ module.exports = Server;
package/src/Util.js ADDED
@@ -0,0 +1,51 @@
1
+ const Constants = require('./Constants');
2
+
3
+ var request = require("request");
4
+
5
+ const callHttpApi = function(log, urlToCall, urlMethod, urlBody, urlForm, urlHeaders, rejectUnauthorized, homeKitCallback, context, onSuccessCallback, onFailureCallback, timeout) {
6
+ if (urlToCall !== "" && context !== Constants.CONTEXT_FROM_WEBHOOK) {
7
+ var theRequest = {
8
+ method : urlMethod,
9
+ url : urlToCall,
10
+ timeout : timeout || Constants.DEFAULT_REQUEST_TIMEOUT,
11
+ headers : JSON.parse(urlHeaders),
12
+ rejectUnauthorized: rejectUnauthorized
13
+ };
14
+ if (urlMethod === "POST" || urlMethod === "PUT" || urlMethod === "PATCH") {
15
+ if (urlForm) {
16
+ log("Adding Form " + urlForm);
17
+ theRequest.form = JSON.parse(urlForm);
18
+ }
19
+ else if (urlBody) {
20
+ log("Adding Body " + urlBody);
21
+ theRequest.body = urlBody;
22
+ }
23
+ }
24
+ request(theRequest, (function(err, response, body) {
25
+ var statusCode = response && response.statusCode ? response.statusCode : -1;
26
+ log("Request to '%s' finished with status code '%s' and body '%s'.", urlToCall, statusCode, body, err);
27
+ if (!err && statusCode >= 200 && statusCode < 300) {
28
+ if (onSuccessCallback) {
29
+ onSuccessCallback();
30
+ }
31
+ homeKitCallback(null);
32
+ }
33
+ else {
34
+ if (onFailureCallback) {
35
+ onFailureCallback();
36
+ }
37
+ homeKitCallback(err || new Error("Request to '" + urlToCall + "' was not succesful."));
38
+ }
39
+ }).bind(this));
40
+ }
41
+ else {
42
+ if (onSuccessCallback) {
43
+ onSuccessCallback();
44
+ }
45
+ homeKitCallback(null);
46
+ }
47
+ };
48
+
49
+ module.exports = {
50
+ callHttpApi : callHttpApi
51
+ };
@@ -0,0 +1,136 @@
1
+ const Constants = require('../Constants');
2
+ const Server = require('../Server');
3
+
4
+ var HttpWebHookSensorAccessory = require('./accessories/HttpWebHookSensorAccessory');
5
+ var HttpWebHookSwitchAccessory = require('./accessories/HttpWebHookSwitchAccessory');
6
+ var HttpWebHookPushButtonAccessory = require('./accessories/HttpWebHookPushButtonAccessory');
7
+ var HttpWebHookDoorbellAccessory = require('./accessories/HttpWebHookDoorbellAccessory');
8
+ var HttpWebHookLightBulbAccessory = require('./accessories/HttpWebHookLightBulbAccessory');
9
+ var HttpWebHookThermostatAccessory = require('./accessories/HttpWebHookThermostatAccessory');
10
+ var HttpWebHookOutletAccessory = require('./accessories/HttpWebHookOutletAccessory');
11
+ var HttpWebHookSecurityAccessory = require('./accessories/HttpWebHookSecurityAccessory');
12
+ var HttpWebHookGarageDoorOpenerAccessory = require('./accessories/HttpWebHookGarageDoorOpenerAccessory');
13
+ var HttpWebHookStatelessSwitchAccessory = require('./accessories/HttpWebHookStatelessSwitchAccessory');
14
+ var HttpWebHookLockMechanismAccessory = require('./accessories/HttpWebHookLockMechanismAccessory');
15
+ var HttpWebHookWindowCoveringAccessory = require('./accessories/HttpWebHookWindowCoveringAccessory');
16
+ var HttpWebHookFanv2Accessory = require('./accessories/HttpWebHookFanv2Accessory');
17
+ var HttpWebHookCarbonDioxideSensoryAccessory = require('./accessories/HttpWebHookCarbonDioxideSensorAccessory');
18
+ var HttpWebHookValveAccessory = require('./accessories/HttpWebHookValveAccessory');
19
+
20
+ var Service, Characteristic;
21
+
22
+ function HttpWebHooksPlatform(log, config, homebridge) {
23
+ Service = homebridge.hap.Service;
24
+ Characteristic = homebridge.hap.Characteristic;
25
+
26
+ this.log = log;
27
+ this.cacheDirectory = config["cache_directory"] || Constants.DEFAULT_CACHE_DIR;
28
+ this.storage = require('node-persist');
29
+ this.storage.initSync({
30
+ dir : this.cacheDirectory
31
+ });
32
+
33
+ this.sensors = config["sensors"] || [];
34
+ this.switches = config["switches"] || [];
35
+ this.pushButtons = config["pushbuttons"] || [];
36
+ this.doorbells = config["doorbells"] || [];
37
+ this.lights = config["lights"] || [];
38
+ this.thermostats = config["thermostats"] || [];
39
+ this.outlets = config["outlets"] || [];
40
+ this.security = config["security"] || [];
41
+ this.garageDoorOpeners = config["garagedooropeners"] || [];
42
+ this.statelessSwitches = config["statelessswitches"] || [];
43
+ this.windowCoverings = config["windowcoverings"] || [];
44
+ this.lockMechanisms = config["lockmechanisms"] || [];
45
+ this.fanv2s = config["fanv2s"] || [];
46
+ this.co2sensors = config["co2sensors"] || [];
47
+ this.valves = config["valves"] || [];
48
+
49
+ this.server = new Server(Service, Characteristic, this, config);
50
+ };
51
+
52
+ HttpWebHooksPlatform.prototype.accessories = function(callback) {
53
+ var accessories = [];
54
+
55
+ for (var i = 0; i < this.sensors.length; i++) {
56
+ var sensor = new HttpWebHookSensorAccessory(Service, Characteristic, this, this.sensors[i]);
57
+ accessories.push(sensor);
58
+ }
59
+
60
+ for (var i = 0; i < this.switches.length; i++) {
61
+ var switchAccessory = new HttpWebHookSwitchAccessory(Service, Characteristic, this, this.switches[i]);
62
+ accessories.push(switchAccessory);
63
+ }
64
+
65
+ for (var i = 0; i < this.pushButtons.length; i++) {
66
+ var pushButtonsAccessory = new HttpWebHookPushButtonAccessory(Service, Characteristic, this, this.pushButtons[i]);
67
+ accessories.push(pushButtonsAccessory);
68
+ }
69
+
70
+ for (var i = 0; i < this.doorbells.length; i++) {
71
+ var doorbellAccessory = new HttpWebHookDoorbellAccessory(Service, Characteristic, this, this.doorbells[i]);
72
+ accessories.push(doorbellAccessory);
73
+ }
74
+
75
+ for (var i = 0; i < this.lights.length; i++) {
76
+ var lightAccessory = new HttpWebHookLightBulbAccessory(Service, Characteristic, this, this.lights[i]);
77
+ accessories.push(lightAccessory);
78
+ }
79
+
80
+ for (var i = 0; i < this.thermostats.length; i++) {
81
+ var thermostatAccessory = new HttpWebHookThermostatAccessory(Service, Characteristic, this, this.thermostats[i]);
82
+ accessories.push(thermostatAccessory);
83
+ }
84
+
85
+ for (var i = 0; i < this.outlets.length; i++) {
86
+ var outletAccessory = new HttpWebHookOutletAccessory(Service, Characteristic, this, this.outlets[i]);
87
+ accessories.push(outletAccessory);
88
+ }
89
+
90
+ for (var i = 0; i < this.security.length; i++) {
91
+ var securityAccessory = new HttpWebHookSecurityAccessory(Service, Characteristic, this, this.security[i]);
92
+ accessories.push(securityAccessory);
93
+ }
94
+
95
+ for (var i = 0; i < this.garageDoorOpeners.length; i++) {
96
+ var garageDoorOpenerAccessory = new HttpWebHookGarageDoorOpenerAccessory(Service, Characteristic, this, this.garageDoorOpeners[i]);
97
+ accessories.push(garageDoorOpenerAccessory);
98
+ }
99
+
100
+ for (var i = 0; i < this.windowCoverings.length; i++) {
101
+ var WindowCoveringAccessory = new HttpWebHookWindowCoveringAccessory(Service, Characteristic, this, this.windowCoverings[i]);
102
+ accessories.push(WindowCoveringAccessory);
103
+ }
104
+
105
+ for (var i = 0; i < this.statelessSwitches.length; i++) {
106
+ var statelessSwitchAccessory = new HttpWebHookStatelessSwitchAccessory(Service, Characteristic, this, this.statelessSwitches[i]);
107
+ accessories.push(statelessSwitchAccessory);
108
+ }
109
+
110
+ for (var i = 0; i < this.lockMechanisms.length; i++) {
111
+ var lockMechanismAccessory = new HttpWebHookLockMechanismAccessory(Service, Characteristic, this, this.lockMechanisms[i]);
112
+ accessories.push(lockMechanismAccessory);
113
+ }
114
+
115
+ for (var i = 0; i < this.fanv2s.length; i++) {
116
+ var fanv2Accessory = new HttpWebHookFanv2Accessory(Service, Characteristic, this, this.fanv2s[i]);
117
+ accessories.push(fanv2Accessory);
118
+ }
119
+
120
+ for (var i = 0; i < this.co2sensors.length; i++) {
121
+ var co2sensorAccessory = new HttpWebHookCarbonDioxideSensoryAccessory(Service, Characteristic, this, this.co2sensors[i]);
122
+ accessories.push(co2sensorAccessory);
123
+ }
124
+
125
+ for (var i = 0; i < this.valves.length; i++) {
126
+ var valveAccessory = new HttpWebHookValveAccessory(Service, Characteristic, this, this.valves[i]);
127
+ accessories.push(valveAccessory);
128
+ }
129
+
130
+ this.server.setAccessories(accessories);
131
+ this.server.start();
132
+
133
+ callback(accessories);
134
+ };
135
+
136
+ module.exports = HttpWebHooksPlatform;
@@ -0,0 +1,75 @@
1
+ const Constants = require('../../Constants');
2
+
3
+ function HttpWebHookCarbonDioxideSensorAccessory(ServiceParam, CharacteristicParam, platform, sensorConfig) {
4
+ Service = ServiceParam;
5
+ Characteristic = CharacteristicParam;
6
+
7
+ this.platform = platform;
8
+ this.log = platform.log;
9
+ this.storage = platform.storage;
10
+
11
+ this.id = sensorConfig["id"];
12
+ this.name = sensorConfig["name"];
13
+ this.type = "co2";
14
+ this.co2PeakLevel = sensorConfig["co2_peak_level"] || 1200;
15
+
16
+ this.informationService = new Service.AccessoryInformation();
17
+ this.informationService.setCharacteristic(Characteristic.Manufacturer, "HttpWebHooksPlatform");
18
+ this.informationService.setCharacteristic(Characteristic.Model, "HttpWebHookCarbonDioxideSensorAccessory-" + this.name);
19
+ this.informationService.setCharacteristic(Characteristic.SerialNumber, "HttpWebHookCarbonDioxideSensorAccessory-" + this.id);
20
+
21
+ this.service = new Service.CarbonDioxideSensor(this.name);
22
+ this.service.getCharacteristic(Characteristic.CarbonDioxideLevel).on('get', this.getCarbonDioxideLevel.bind(this));
23
+ this.service.getCharacteristic(Characteristic.CarbonDioxideDetected).on('get', this.getCarbonDioxideDetected.bind(this));
24
+ }
25
+
26
+ HttpWebHookCarbonDioxideSensorAccessory.prototype.changeFromServer = function(urlParams) {
27
+ var cached = this.storage.getItemSync("http-webhook-" + this.id) || 0;
28
+ if (urlParams.value === undefined) {
29
+ this.log.debug(this.name + ": No urlValue");
30
+ return {
31
+ "success" : true,
32
+ "state" : cached
33
+ };
34
+ }
35
+ var urlValue = urlParams.value;
36
+ var co2Detected = urlValue > this.co2PeakLevel;
37
+ this.log.debug(this.name + ": urlValue: "+ urlValue);
38
+ this.log.debug(this.name + ": co2Detected: "+ co2Detected);
39
+ this.storage.setItemSync("http-webhook-carbon-dioxide-level-" + this.id, urlValue);
40
+ this.storage.setItemSync("http-webhook-carbon-dioxide-detected-" + this.id, co2Detected);
41
+ this.log.debug(this.name + ": cached: "+ cached);
42
+ this.log.debug(this.name + ": cached !== urlValue: "+ (cached !== urlValue));
43
+ if (cached !== urlValue) {
44
+ this.log(this.name + ": Change HomeKit value for " + this.type + " sensor to '%s'.", urlValue);
45
+ this.service.getCharacteristic(Characteristic.CarbonDioxideLevel).updateValue(urlValue, undefined, Constants.CONTEXT_FROM_WEBHOOK);
46
+ this.service.getCharacteristic(Characteristic.CarbonDioxideDetected).updateValue(co2Detected ? Characteristic.CarbonDioxideDetected.CO2_LEVELS_ABNORMAL : Characteristic.CarbonDioxideDetected.CO2_LEVELS_NORMAL, undefined, Constants.CONTEXT_FROM_WEBHOOK);
47
+ }
48
+ return {
49
+ "success" : true
50
+ };
51
+ }
52
+
53
+ HttpWebHookCarbonDioxideSensorAccessory.prototype.getCarbonDioxideLevel = function(callback) {
54
+ this.log.debug(this.name + ": Getting carbon dioxide level for '%s'...", this.id);
55
+ var temp = this.storage.getItemSync("http-webhook-carbon-dioxide-level-" + this.id);
56
+ if (temp === undefined) {
57
+ temp = 0;
58
+ }
59
+ callback(null, temp);
60
+ };
61
+
62
+ HttpWebHookCarbonDioxideSensorAccessory.prototype.getCarbonDioxideDetected = function(callback) {
63
+ this.log.debug(this.name + ": Getting carbon dioxide detected state for '%s'...", this.id);
64
+ var state = this.storage.getItemSync("http-webhook-carbon-dioxide-detected-" + this.id);
65
+ if (state === undefined) {
66
+ state = false;
67
+ }
68
+ callback(null, state ? Characteristic.CarbonDioxideDetected.CO2_LEVELS_ABNORMAL : Characteristic.CarbonDioxideDetected.CO2_LEVELS_NORMAL);
69
+ };
70
+
71
+ HttpWebHookCarbonDioxideSensorAccessory.prototype.getServices = function() {
72
+ return [ this.service, this.informationService ];
73
+ };
74
+
75
+ module.exports = HttpWebHookCarbonDioxideSensorAccessory;