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.
- package/CHANGELOG.md +543 -0
- package/LICENSE +674 -0
- package/README.md +505 -0
- package/config.schema.json +1821 -0
- package/docs/COMPATIBILITY.md +73 -0
- package/index.js +35 -0
- package/package.json +56 -0
- package/src/Constants.js +12 -0
- package/src/Server.js +192 -0
- package/src/Util.js +51 -0
- package/src/homekit/HttpWebHooksPlatform.js +136 -0
- package/src/homekit/accessories/HttpWebHookCarbonDioxideSensorAccessory.js +75 -0
- package/src/homekit/accessories/HttpWebHookDoorbellAccessory.js +139 -0
- package/src/homekit/accessories/HttpWebHookFanv2Accessory.js +320 -0
- package/src/homekit/accessories/HttpWebHookGarageDoorOpenerAccessory.js +142 -0
- package/src/homekit/accessories/HttpWebHookLightBulbAccessory.js +153 -0
- package/src/homekit/accessories/HttpWebHookLockMechanismAccessory.js +125 -0
- package/src/homekit/accessories/HttpWebHookOutletAccessory.js +125 -0
- package/src/homekit/accessories/HttpWebHookPushButtonAccessory.js +93 -0
- package/src/homekit/accessories/HttpWebHookSecurityAccessory.js +104 -0
- package/src/homekit/accessories/HttpWebHookSensorAccessory.js +169 -0
- package/src/homekit/accessories/HttpWebHookStatelessSwitchAccessory.js +101 -0
- package/src/homekit/accessories/HttpWebHookSwitchAccessory.js +95 -0
- package/src/homekit/accessories/HttpWebHookThermostatAccessory.js +164 -0
- package/src/homekit/accessories/HttpWebHookValveAccessory.js +151 -0
- package/src/homekit/accessories/HttpWebHookWindowCoveringAccessory.js +203 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
const Constants = require('../../Constants');
|
|
2
|
+
|
|
3
|
+
function HttpWebHookDoorbellAccessory(ServiceParam, CharacteristicParam, platform, doorbellConfig) {
|
|
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 = doorbellConfig["id"];
|
|
12
|
+
this.type = "doorbell";
|
|
13
|
+
this.name = doorbellConfig["name"];
|
|
14
|
+
|
|
15
|
+
var single_press = doorbellConfig["single_press"] === undefined ? true : doorbellConfig["single_press"];
|
|
16
|
+
var double_press = doorbellConfig["double_press"] === undefined ? true : doorbellConfig["double_press"];
|
|
17
|
+
var long_press = doorbellConfig["long_press"] === undefined ? true : doorbellConfig["long_press"];
|
|
18
|
+
|
|
19
|
+
// first service must be a StatelessProgrammableSwitch to be supported in the Home app. Only need one button for the doorbell
|
|
20
|
+
this.service = [];
|
|
21
|
+
var button = new Service.StatelessProgrammableSwitch(this.name,'sps');
|
|
22
|
+
button.getCharacteristic(Characteristic.ProgrammableSwitchEvent).setProps(GetDoorbellStatelessSwitchProps(single_press, double_press, long_press));
|
|
23
|
+
this.service.push(button);
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
// add the Doorbell as a service
|
|
27
|
+
var doorbell = new Service.Doorbell(this.name,'db');
|
|
28
|
+
doorbell.getCharacteristic(Characteristic.ProgrammableSwitchEvent).setProps(GetDoorbellStatelessSwitchProps(single_press, double_press, long_press));
|
|
29
|
+
this.service.push(doorbell);
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
// add the AccessoryInformation as a service
|
|
33
|
+
var informationService = new Service.AccessoryInformation();
|
|
34
|
+
informationService.setCharacteristic(Characteristic.Manufacturer, "HttpWebHooksPlatform");
|
|
35
|
+
informationService.setCharacteristic(Characteristic.Model, "HttpWebHookDoorbellAccessory-" + this.name);
|
|
36
|
+
informationService.setCharacteristic(Characteristic.SerialNumber, this.id);
|
|
37
|
+
this.service.push(informationService);
|
|
38
|
+
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
HttpWebHookDoorbellAccessory.prototype.changeFromServer = function(urlParams) {
|
|
42
|
+
if (urlParams.event && urlParams.event) {
|
|
43
|
+
// loop each service to find the Doorbell and StatelessProgrammableSwitch services
|
|
44
|
+
for (var index = 0; index < this.service.length; index++) {
|
|
45
|
+
var serviceName = this.service[index].getCharacteristic(Characteristic.Name).value;
|
|
46
|
+
var serviceSubtype = this.service[index].subtype;
|
|
47
|
+
var validValues = this.service[index].getCharacteristic(Characteristic.ProgrammableSwitchEvent).props.validValues;
|
|
48
|
+
|
|
49
|
+
// for service subtypes sps and db, update the value
|
|
50
|
+
// db is the Doorbell, updateValue causes the HomeKit notification to be sent
|
|
51
|
+
// sps is the StatelessProgrammableSwitch, updateValue causes any programmed switch actions to occur
|
|
52
|
+
if ((['db','sps'].includes(serviceSubtype)) ) {
|
|
53
|
+
if (validValues.includes(Number(urlParams.event))) {
|
|
54
|
+
// event value is valid
|
|
55
|
+
// we need updates for 2 x services, but we only want to do 1 x logging and so log only for the doorbell update
|
|
56
|
+
if (serviceSubtype === 'db') {
|
|
57
|
+
this.log(this.name + ": Pressing '%s' with event '%i'", serviceName, urlParams.event);
|
|
58
|
+
this.service[index].getCharacteristic(Characteristic.ProgrammableSwitchEvent).updateValue(urlParams.event, undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
59
|
+
}
|
|
60
|
+
// for the sps just do the update, no logging
|
|
61
|
+
if (serviceSubtype === 'sps') {
|
|
62
|
+
this.service[index].getCharacteristic(Characteristic.ProgrammableSwitchEvent).updateValue(urlParams.event, undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
// event value is invalid
|
|
66
|
+
var errorText = "event value " + urlParams.event + " is outside of valid values: " + validValues;
|
|
67
|
+
this.log.warn(this.name + ": WARNING: " + errorText);
|
|
68
|
+
return {
|
|
69
|
+
"error" : errorText
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
"success" : true
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function GetDoorbellStatelessSwitchProps(single_press, double_press, long_press) {
|
|
82
|
+
var props;
|
|
83
|
+
if (single_press && !double_press && !long_press) {
|
|
84
|
+
props = {
|
|
85
|
+
minValue : Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
|
|
86
|
+
maxValue : Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
|
|
87
|
+
validValues : [ Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS ]
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (single_press && double_press && !long_press) {
|
|
91
|
+
props = {
|
|
92
|
+
minValue : Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
|
|
93
|
+
maxValue : Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS,
|
|
94
|
+
validValues : [ Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS, Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS ]
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (single_press && !double_press && long_press) {
|
|
98
|
+
props = {
|
|
99
|
+
minValue : Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
|
|
100
|
+
maxValue : Characteristic.ProgrammableSwitchEvent.LONG_PRESS,
|
|
101
|
+
validValues : [ Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS, Characteristic.ProgrammableSwitchEvent.LONG_PRESS ]
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (!single_press && double_press && !long_press) {
|
|
105
|
+
props = {
|
|
106
|
+
minValue : Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS,
|
|
107
|
+
maxValue : Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS,
|
|
108
|
+
validValues : [ Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS ]
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (!single_press && double_press && long_press) {
|
|
112
|
+
props = {
|
|
113
|
+
minValue : Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS,
|
|
114
|
+
maxValue : Characteristic.ProgrammableSwitchEvent.LONG_PRESS,
|
|
115
|
+
validValues : [ Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS, Characteristic.ProgrammableSwitchEvent.LONG_PRESS ]
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (!single_press && !double_press && long_press) {
|
|
119
|
+
props = {
|
|
120
|
+
minValue : Characteristic.ProgrammableSwitchEvent.LONG_PRESS,
|
|
121
|
+
maxValue : Characteristic.ProgrammableSwitchEvent.LONG_PRESS,
|
|
122
|
+
validValues : [ Characteristic.ProgrammableSwitchEvent.LONG_PRESS ]
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (single_press && double_press && long_press) {
|
|
126
|
+
props = {
|
|
127
|
+
minValue : Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
|
|
128
|
+
maxValue : Characteristic.ProgrammableSwitchEvent.LONG_PRESS,
|
|
129
|
+
validValues : [ Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS, Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS, Characteristic.ProgrammableSwitchEvent.LONG_PRESS ]
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return props;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
HttpWebHookDoorbellAccessory.prototype.getServices = function() {
|
|
136
|
+
return this.service;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
module.exports = HttpWebHookDoorbellAccessory;
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
const { parse } = require('node-persist');
|
|
2
|
+
const Constants = require('../../Constants');
|
|
3
|
+
const Util = require('../../Util');
|
|
4
|
+
|
|
5
|
+
function HttpWebHookFanv2Accessory(ServiceParam, CharacteristicParam, platform, fanv2Config) {
|
|
6
|
+
Service = ServiceParam;
|
|
7
|
+
Characteristic = CharacteristicParam;
|
|
8
|
+
|
|
9
|
+
this.platform = platform;
|
|
10
|
+
this.log = platform.log;
|
|
11
|
+
this.storage = platform.storage;
|
|
12
|
+
|
|
13
|
+
this.id = fanv2Config["id"];
|
|
14
|
+
this.type = "fanv2";
|
|
15
|
+
this.name = fanv2Config["name"];
|
|
16
|
+
this.rejectUnauthorized = fanv2Config["rejectUnauthorized"] === undefined ? true :
|
|
17
|
+
fanv2Config["rejectUnauthorized"] === true;
|
|
18
|
+
|
|
19
|
+
this.onURL = fanv2Config["on_url"] || "";
|
|
20
|
+
this.onMethod = fanv2Config["on_method"] || "GET";
|
|
21
|
+
this.onBody = fanv2Config["on_body"] || "";
|
|
22
|
+
this.onForm = fanv2Config["on_form"] || "";
|
|
23
|
+
this.onHeaders = fanv2Config["on_headers"] || "{}";
|
|
24
|
+
this.offURL = fanv2Config["off_url"] || "";
|
|
25
|
+
this.offMethod = fanv2Config["off_method"] || "GET";
|
|
26
|
+
this.offBody = fanv2Config["off_body"] || "";
|
|
27
|
+
this.offForm = fanv2Config["off_form"] || "";
|
|
28
|
+
this.offHeaders = fanv2Config["off_headers"] || "{}";
|
|
29
|
+
this.speedURL = fanv2Config["speed_url"] || "";
|
|
30
|
+
this.speedMethod = fanv2Config["speed_method"] || "GET";
|
|
31
|
+
this.speedBody = fanv2Config["speed_body"] || "";
|
|
32
|
+
this.speedForm = fanv2Config["speed_form"] || "";
|
|
33
|
+
this.speedHeaders = fanv2Config["speed_headers"] || "{}";
|
|
34
|
+
this.speedFactor = fanv2Config["speed_factor"] || 1;
|
|
35
|
+
|
|
36
|
+
this.enableLockPhysicalControls = fanv2Config["enableLockPhysicalControls"] || false;
|
|
37
|
+
this.lockURL = fanv2Config["lock_url"] || "";
|
|
38
|
+
this.lockMethod = fanv2Config["lock_method"] || "GET";
|
|
39
|
+
this.lockBody = fanv2Config["lock_body"] || "";
|
|
40
|
+
this.lockForm = fanv2Config["lock_form"] || "";
|
|
41
|
+
this.lockHeaders = fanv2Config["lock_headers"] || "{}";
|
|
42
|
+
this.unlockURL = fanv2Config["unlock_url"] || "";
|
|
43
|
+
this.unlockMethod = fanv2Config["unlock_method"] || "GET";
|
|
44
|
+
this.unlockBody = fanv2Config["unlock_body"] || "";
|
|
45
|
+
this.unlockForm = fanv2Config["unlock_form"] || "";
|
|
46
|
+
this.unlockHeaders = fanv2Config["unlock_headers"] || "{}";
|
|
47
|
+
|
|
48
|
+
this.enableTargetStateControls = fanv2Config["enableTargetStateControls"] || false;
|
|
49
|
+
this.targetStateURL = fanv2Config["target_state_url"] || "";
|
|
50
|
+
this.targetStateMethod = fanv2Config["target_state_method"] || "GET";
|
|
51
|
+
this.targetStateBody = fanv2Config["target_state_body"] || "";
|
|
52
|
+
this.targetStateForm = fanv2Config["target_state_form"] || "";
|
|
53
|
+
this.targetStateHeaders = fanv2Config["target_state_headers"] || "{}";
|
|
54
|
+
|
|
55
|
+
this.enableSwingModeControls = fanv2Config["enableSwingModeControls"] || false;
|
|
56
|
+
this.swingModeURL = fanv2Config["swing_mode_url"] || "";
|
|
57
|
+
this.swingModeMethod = fanv2Config["swing_mode_method"] || "GET";
|
|
58
|
+
this.swingModeBody = fanv2Config["swing_mode_body"] || "";
|
|
59
|
+
this.swingModeForm = fanv2Config["swing_mode_form"] || "";
|
|
60
|
+
this.swingModeHeaders = fanv2Config["swing_mode_headers"] || "{}";
|
|
61
|
+
|
|
62
|
+
this.rotationDirectionURL = fanv2Config["rotation_direction_url"] || "";
|
|
63
|
+
this.rotationDirectionMethod = fanv2Config["rotation_direction_method"] || "GET";
|
|
64
|
+
this.rotationDirectionBody = fanv2Config["rotation_direction_body"] || "";
|
|
65
|
+
this.rotationDirectionForm = fanv2Config["rotation_direction_form"] || "";
|
|
66
|
+
this.rotationDirectionHeaders = fanv2Config["rotation_direction_headers"] || "{}";
|
|
67
|
+
|
|
68
|
+
this.informationService = new Service.AccessoryInformation();
|
|
69
|
+
this.informationService.setCharacteristic(Characteristic.Manufacturer, "HttpWebHooksPlatform");
|
|
70
|
+
this.informationService.setCharacteristic(Characteristic.Model, "HttpWebHookFanv2Accessory-" + this.name);
|
|
71
|
+
this.informationService.setCharacteristic(Characteristic.SerialNumber, "HttpWebHookFanv2Accessory-" + this.id);
|
|
72
|
+
|
|
73
|
+
this.service = new Service.Fanv2(this.name);
|
|
74
|
+
this.service.getCharacteristic(Characteristic.Active).on('get', this.getState.bind(this)).on('set', this.setState.bind(this));
|
|
75
|
+
this.service.getCharacteristic(Characteristic.RotationSpeed).on('get', this.getSpeed.bind(this)).on('set', this.setSpeed.bind(this));
|
|
76
|
+
this.service.getCharacteristic(Characteristic.RotationDirection).on('get', this.getRotationDirection.bind(this)).on('set', this.setRotationDirection.bind(this));
|
|
77
|
+
|
|
78
|
+
if (this.enableLockPhysicalControls) {
|
|
79
|
+
this.service.getCharacteristic(Characteristic.LockPhysicalControls).on('get', this.getLockState.bind(this)).on('set', this.setLockState.bind(this));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (this.enableTargetStateControls) {
|
|
83
|
+
this.service.getCharacteristic(Characteristic.TargetFanState).on('get', this.getTargetState.bind(this)).on('set', this.setTargetState.bind(this));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (this.enableSwingModeControls) {
|
|
87
|
+
this.service.getCharacteristic(Characteristic.SwingMode).on('get', this.getSwingMode.bind(this)).on('set', this.setSwingMode.bind(this));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
HttpWebHookFanv2Accessory.prototype.changeFromServer = function (urlParams) {
|
|
92
|
+
var cachedState = this.storage.getItemSync("http-webhook-" + this.id);
|
|
93
|
+
if (cachedState === undefined) {
|
|
94
|
+
cachedState = false;
|
|
95
|
+
}
|
|
96
|
+
var state = urlParams.state || cachedState;
|
|
97
|
+
var stateBool = state === "true" || state === true;
|
|
98
|
+
if (urlParams.state != cachedState) {
|
|
99
|
+
this.log(this.name + ": Change state for fanv2 to '%s'.", stateBool);
|
|
100
|
+
this.service.getCharacteristic(Characteristic.Active).updateValue((urlParams.state == "true"), undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
101
|
+
}
|
|
102
|
+
if (urlParams.speed != null) {
|
|
103
|
+
var cachedSpeed = this.storage.getItemSync("http-webhook-speed-" + this.id);
|
|
104
|
+
var speed = parseInt(urlParams.speed);
|
|
105
|
+
if (cachedSpeed != speed) {
|
|
106
|
+
this.log(this.name + ": Change speed for fanv2 to '%d'.", speed);
|
|
107
|
+
this.service.getCharacteristic(Characteristic.RotationSpeed).updateValue(speed, undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (urlParams.swingMode != null && this.enableSwingModeControls) {
|
|
111
|
+
var cachedSwingMode = this.storage.getItemSync("http-webhook-swingmode-" + this.id);
|
|
112
|
+
var swingMode = parseInt(urlParams.swingMode);
|
|
113
|
+
if (cachedSwingMode != swingMode) {
|
|
114
|
+
this.log(this.name + ": Change swing mode for fanv2 to '%d'.", swingMode);
|
|
115
|
+
this.service.getCharacteristic(Characteristic.SwingMode).updateValue(swingMode, undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (urlParams.rotationDirection != null) {
|
|
119
|
+
var cachedRotationDirection = this.storage.getItemSync("http-webhook-rotationdirection-" + this.id);
|
|
120
|
+
var rotationDirection = parseInt(urlParams.rotationDirection);
|
|
121
|
+
if (cachedRotationDirection != rotationDirection) {
|
|
122
|
+
this.log(this.name + ": Change rotation direction for fanv2 to '%d'.", rotationDirection);
|
|
123
|
+
this.service.getCharacteristic(Characteristic.RotationDirection).updateValue(rotationDirection, undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (urlParams.lockstate != null && this.enableLockPhysicalControls) {
|
|
127
|
+
var cachedLockstate = this.storage.getItemSync("http-webhook-lockstate-" + this.id);
|
|
128
|
+
var lockstate = parseInt(urlParams.lockState);
|
|
129
|
+
if (cachedLockstate != lockstate) {
|
|
130
|
+
this.log(this.name + ": Change lock state for fanv2 to '%d'.", lockstate);
|
|
131
|
+
this.service.getCharacteristic(Characteristic.LockPhysicalControls).updateValue(lockstate, undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (urlParams.targetState != null && this.enableTargetStateControls) {
|
|
135
|
+
var cachedTargetstate = this.storage.getItemSync("http-webhook-targetstate-" + this.id);
|
|
136
|
+
var targetState = parseInt(urlParams.targetState);
|
|
137
|
+
if (cachedTargetstate != targetState) {
|
|
138
|
+
this.log(this.name + ": Change target state for fanv2 to '%d'.", targetState);
|
|
139
|
+
this.service.getCharacteristic(Characteristic.TargetFanState).updateValue(targetState, undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
"success": true
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
HttpWebHookFanv2Accessory.prototype.getState = function (callback) {
|
|
148
|
+
this.log.debug(this.name + ": Getting current state for '%s'...", this.id);
|
|
149
|
+
var state = this.storage.getItemSync("http-webhook-" + this.id);
|
|
150
|
+
if (state === undefined) {
|
|
151
|
+
state = false;
|
|
152
|
+
}
|
|
153
|
+
callback(null, state);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
HttpWebHookFanv2Accessory.prototype.setState = function (powerOn, callback, context) {
|
|
157
|
+
this.log(this.name + ": Fanv2 state for '%s'...", this.id);
|
|
158
|
+
this.storage.setItemSync("http-webhook-" + this.id, powerOn);
|
|
159
|
+
var urlToCall = this.onURL;
|
|
160
|
+
var urlMethod = this.onMethod;
|
|
161
|
+
var urlBody = this.onBody;
|
|
162
|
+
var urlForm = this.onForm;
|
|
163
|
+
var urlHeaders = this.onHeaders;
|
|
164
|
+
if (!powerOn) {
|
|
165
|
+
urlToCall = this.offURL;
|
|
166
|
+
urlMethod = this.offMethod;
|
|
167
|
+
urlBody = this.offBody;
|
|
168
|
+
urlForm = this.offForm;
|
|
169
|
+
urlHeaders = this.offHeaders;
|
|
170
|
+
}
|
|
171
|
+
Util.callHttpApi(this.log, urlToCall, urlMethod, urlBody, urlForm, urlHeaders, this.rejectUnauthorized, callback, context);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
HttpWebHookFanv2Accessory.prototype.getSpeed = function (callback) {
|
|
175
|
+
this.log.debug(this.name + ": Getting current speed for '%s'...", this.id);
|
|
176
|
+
var state = this.storage.getItemSync("http-webhook-" + this.id);
|
|
177
|
+
if (state === undefined) {
|
|
178
|
+
state = false;
|
|
179
|
+
}
|
|
180
|
+
var speed = 0;
|
|
181
|
+
if (state) {
|
|
182
|
+
speed = this.storage.getItemSync("http-webhook-speed-" + this.id);
|
|
183
|
+
if (speed === undefined) {
|
|
184
|
+
speed = 100;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
callback(null, parseInt(speed));
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
HttpWebHookFanv2Accessory.prototype.setSpeed = function (speed, callback, context) {
|
|
191
|
+
this.log(this.name + ": Fanv2 rotation speed for '%s'...", this.id);
|
|
192
|
+
var newState = speed > 0;
|
|
193
|
+
this.storage.setItemSync("http-webhook-" + this.id, newState);
|
|
194
|
+
this.storage.setItemSync("http-webhook-speed-" + this.id, speed);
|
|
195
|
+
var speedFactor = this.speedFactor;
|
|
196
|
+
var speedToSet = Math.ceil(speed * speedFactor);
|
|
197
|
+
var urlToCall = this.replaceVariables(this.speedURL, newState, speedToSet);
|
|
198
|
+
var urlMethod = this.speedMethod;
|
|
199
|
+
var urlBody = this.speedBody;
|
|
200
|
+
var urlForm = this.speedForm;
|
|
201
|
+
var urlHeaders = this.speedHeaders;
|
|
202
|
+
|
|
203
|
+
if (urlForm) {
|
|
204
|
+
urlForm = this.replaceVariables(urlForm, newState, speedToSet);
|
|
205
|
+
}
|
|
206
|
+
else if (urlBody) {
|
|
207
|
+
urlBody = this.replaceVariables(urlBody, newState, speedToSet);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
Util.callHttpApi(this.log, urlToCall, urlMethod, urlBody, urlForm, urlHeaders, this.rejectUnauthorized, callback, context);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
HttpWebHookFanv2Accessory.prototype.getLockState = function (callback) {
|
|
214
|
+
this.log.debug(this.name + ": Getting current lock state for '%s'...", this.id);
|
|
215
|
+
var lockstate = this.storage.getItemSync("http-webhook-lockstate-" + this.id);
|
|
216
|
+
if (lockstate === undefined) {
|
|
217
|
+
lockstate = false;
|
|
218
|
+
}
|
|
219
|
+
callback(null, lockstate);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
HttpWebHookFanv2Accessory.prototype.setLockState = function (lockState, callback, context) {
|
|
223
|
+
this.log(this.name + ": Fanv2 lock state for '%s'...", this.id);
|
|
224
|
+
this.storage.setItemSync("http-webhook-lockstate-" + this.id, lockState);
|
|
225
|
+
var urlToCall = this.lockURL;
|
|
226
|
+
var urlMethod = this.lockMethod;
|
|
227
|
+
var urlBody = this.lockBody;
|
|
228
|
+
var urlForm = this.lockForm;
|
|
229
|
+
var urlHeaders = this.lockHeaders;
|
|
230
|
+
if (!lockState) {
|
|
231
|
+
urlToCall = this.unlockURL;
|
|
232
|
+
urlMethod = this.unlockMethod;
|
|
233
|
+
urlBody = this.unlockBody;
|
|
234
|
+
urlForm = this.unlockForm;
|
|
235
|
+
urlHeaders = this.unlockHeaders;
|
|
236
|
+
}
|
|
237
|
+
Util.callHttpApi(this.log, urlToCall, urlMethod, urlBody, urlForm, urlHeaders, this.rejectUnauthorized, callback, context);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
HttpWebHookFanv2Accessory.prototype.getTargetState = function (callback) {
|
|
241
|
+
this.log.debug(this.name + ": Getting current target state for '%s'...", this.id);
|
|
242
|
+
var targetState = this.storage.getItemSync("http-webhook-targetstate-" + this.id);
|
|
243
|
+
if (targetState === undefined) {
|
|
244
|
+
targetState = false;
|
|
245
|
+
}
|
|
246
|
+
callback(null, targetState);
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
HttpWebHookFanv2Accessory.prototype.setTargetState = function (targetState, callback, context) {
|
|
250
|
+
this.log(this.name + ": Fanv2 target state for '%s'...", this.id);
|
|
251
|
+
this.storage.setItemSync("http-webhook-targetstate-" + this.id, targetState);
|
|
252
|
+
var state = this.storage.getItemSync("http-webhook-" + this.id);
|
|
253
|
+
if (state === undefined) {
|
|
254
|
+
state = false;
|
|
255
|
+
}
|
|
256
|
+
var urlToCall = this.targetStateURL.replace("%targetState", targetState);
|
|
257
|
+
var urlMethod = this.targetStateMethod;
|
|
258
|
+
var urlBody = this.targetStateBody.replace("%targetState", targetState);;
|
|
259
|
+
var urlForm = this.targetStateForm;
|
|
260
|
+
var urlHeaders = this.targetStateHeaders;
|
|
261
|
+
|
|
262
|
+
Util.callHttpApi(this.log, urlToCall, urlMethod, urlBody, urlForm, urlHeaders, this.rejectUnauthorized, callback, context);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
HttpWebHookFanv2Accessory.prototype.getSwingMode = function (callback) {
|
|
266
|
+
this.log.debug(this.name + ": Getting current swing mode for '%s'...", this.id);
|
|
267
|
+
var swingMode = this.storage.getItemSync("http-webhook-swingmode-" + this.id);
|
|
268
|
+
if (swingMode === undefined) {
|
|
269
|
+
swingMode = false;
|
|
270
|
+
}
|
|
271
|
+
callback(null, swingMode);
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
HttpWebHookFanv2Accessory.prototype.setSwingMode = function (swingMode, callback, context) {
|
|
275
|
+
this.log(this.name + ": Fanv2 swing mode for '%s'...", this.id);
|
|
276
|
+
this.storage.setItemSync("http-webhook-swingmode-" + this.id, swingMode);
|
|
277
|
+
var state = this.storage.getItemSync("http-webhook-" + this.id);
|
|
278
|
+
if (state === undefined) {
|
|
279
|
+
state = false;
|
|
280
|
+
}
|
|
281
|
+
var urlToCall = this.swingModeURL.replace("%swingMode", swingMode);
|
|
282
|
+
var urlMethod = this.swingModeMethod;
|
|
283
|
+
var urlBody = this.swingModeBody.replace("%swingMode", swingMode);;
|
|
284
|
+
var urlForm = this.swingModeForm;
|
|
285
|
+
var urlHeaders = this.swingModeHeaders;
|
|
286
|
+
|
|
287
|
+
Util.callHttpApi(this.log, urlToCall, urlMethod, urlBody, urlForm, urlHeaders, this.rejectUnauthorized, callback, context);
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
HttpWebHookFanv2Accessory.prototype.getRotationDirection = function (callback) {
|
|
291
|
+
this.log.debug(this.name + ": Getting current rotation direction for '%s'...", this.id);
|
|
292
|
+
var rotationDirection = this.storage.getItemSync("http-webhook-rotationdirection-" + this.id);
|
|
293
|
+
if (rotationDirection === undefined) {
|
|
294
|
+
rotationDirection = false;
|
|
295
|
+
}
|
|
296
|
+
callback(null, rotationDirection);
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
HttpWebHookFanv2Accessory.prototype.setRotationDirection = function (rotationDirection, callback, context) {
|
|
300
|
+
this.log(this.name + ": Fanv2 rotation direction for '%s'...", this.id);
|
|
301
|
+
this.storage.setItemSync("http-webhook-rotationdirection-" + this.id, rotationDirection);
|
|
302
|
+
var urlToCall = this.rotationDirectionURL.replace("%rotationDirection", rotationDirection);
|
|
303
|
+
var urlMethod = this.rotationDirectionMethod;
|
|
304
|
+
var urlBody = this.rotationDirectionBody.replace("%rotationDirection", rotationDirection);;
|
|
305
|
+
var urlForm = this.rotationDirectionForm;
|
|
306
|
+
var urlHeaders = this.rotationDirectionHeaders;
|
|
307
|
+
|
|
308
|
+
Util.callHttpApi(this.log, urlToCall, urlMethod, urlBody, urlForm, urlHeaders, this.rejectUnauthorized, callback, context);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
HttpWebHookFanv2Accessory.prototype.replaceVariables = function (text, state, speed) {
|
|
312
|
+
return text.replace("%statusPlaceholder", state).replace("%speedPlaceholder", speed);
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
HttpWebHookFanv2Accessory.prototype.getServices = function () {
|
|
317
|
+
return [this.service, this.informationService];
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
module.exports = HttpWebHookFanv2Accessory;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
const Constants = require('../../Constants');
|
|
2
|
+
const Util = require('../../Util');
|
|
3
|
+
|
|
4
|
+
function HttpWebHookGarageDoorOpenerAccessory(ServiceParam, CharacteristicParam, platform, garageDoorOpenerConfig) {
|
|
5
|
+
Service = ServiceParam;
|
|
6
|
+
Characteristic = CharacteristicParam;
|
|
7
|
+
|
|
8
|
+
this.platform = platform;
|
|
9
|
+
this.log = platform.log;
|
|
10
|
+
this.storage = platform.storage;
|
|
11
|
+
|
|
12
|
+
this.id = garageDoorOpenerConfig["id"];
|
|
13
|
+
this.name = garageDoorOpenerConfig["name"];
|
|
14
|
+
this.type = "garagedooropener";
|
|
15
|
+
this.rejectUnauthorized = garageDoorOpenerConfig["rejectUnauthorized"] === undefined ? true: garageDoorOpenerConfig["rejectUnauthorized"] === true;
|
|
16
|
+
this.setTargetDoorStateOpenURL = garageDoorOpenerConfig["open_url"] || "";
|
|
17
|
+
this.setTargetDoorStateOpenMethod = garageDoorOpenerConfig["open_method"] || "GET";
|
|
18
|
+
this.setTargetDoorStateOpenBody = garageDoorOpenerConfig["open_body"] || "";
|
|
19
|
+
this.setTargetDoorStateOpenForm = garageDoorOpenerConfig["open_form"] || "";
|
|
20
|
+
this.setTargetDoorStateOpenHeaders = garageDoorOpenerConfig["open_headers"] || "{}";
|
|
21
|
+
this.setTargetDoorStateCloseURL = garageDoorOpenerConfig["close_url"] || "";
|
|
22
|
+
this.setTargetDoorStateCloseMethod = garageDoorOpenerConfig["close_method"] || "GET";
|
|
23
|
+
this.setTargetDoorStateCloseBody = garageDoorOpenerConfig["close_body"] || "";
|
|
24
|
+
this.setTargetDoorStateCloseForm = garageDoorOpenerConfig["close_form"] || "";
|
|
25
|
+
this.setTargetDoorStateCloseHeaders = garageDoorOpenerConfig["close_headers"] || "{}";
|
|
26
|
+
|
|
27
|
+
this.informationService = new Service.AccessoryInformation();
|
|
28
|
+
this.informationService.setCharacteristic(Characteristic.Manufacturer, "HttpWebHooksPlatform");
|
|
29
|
+
this.informationService.setCharacteristic(Characteristic.Model, "HttpWebHookGarageDoorOpenerAccessory-" + this.name);
|
|
30
|
+
this.informationService.setCharacteristic(Characteristic.SerialNumber, "HttpWebHookGarageDoorOpenerAccessory-" + this.id);
|
|
31
|
+
|
|
32
|
+
this.service = new Service.GarageDoorOpener(this.name);
|
|
33
|
+
this.service.getCharacteristic(Characteristic.TargetDoorState).on('get', this.getTargetDoorState.bind(this)).on('set', this.setTargetDoorState.bind(this));
|
|
34
|
+
this.service.getCharacteristic(Characteristic.CurrentDoorState).on('get', this.getCurrentDoorState.bind(this));
|
|
35
|
+
this.service.getCharacteristic(Characteristic.ObstructionDetected).on('get', this.getObstructionDetected.bind(this));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
HttpWebHookGarageDoorOpenerAccessory.prototype.changeFromServer = function(urlParams) {
|
|
39
|
+
if (urlParams.currentdoorstate != null) {
|
|
40
|
+
var cachedCurrentDoorState = this.storage.getItemSync("http-webhook-current-door-state-" + this.id);
|
|
41
|
+
if (cachedCurrentDoorState === undefined) {
|
|
42
|
+
cachedCurrentDoorState = Characteristic.CurrentDoorState.CLOSED;
|
|
43
|
+
}
|
|
44
|
+
this.storage.setItemSync("http-webhook-current-door-state-" + this.id, urlParams.currentdoorstate);
|
|
45
|
+
if (cachedCurrentDoorState !== urlParams.currentdoorstate) {
|
|
46
|
+
if (urlParams.currentdoorstate) {
|
|
47
|
+
this.log(this.name + ": Change Current Door State for garage door opener to '%s'.", urlParams.currentdoorstate);
|
|
48
|
+
this.service.getCharacteristic(Characteristic.CurrentDoorState).updateValue(urlParams.currentdoorstate, undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (urlParams.targetdoorstate != null) {
|
|
53
|
+
var cachedTargetDoorState = this.storage.getItemSync("http-webhook-target-door-state-" + this.id);
|
|
54
|
+
if (cachedTargetDoorState === undefined) {
|
|
55
|
+
cachedTargetDoorState = Characteristic.TargetDoorState.CLOSED;
|
|
56
|
+
}
|
|
57
|
+
this.storage.setItemSync("http-webhook-target-door-state-" + this.id, urlParams.targetdoorstate);
|
|
58
|
+
if (cachedTargetDoorState !== urlParams.targetdoorstate) {
|
|
59
|
+
if (urlParams.targetdoorstate) {
|
|
60
|
+
this.log(this.name + ": Change Target Door State for garage door opener to '%s'.", urlParams.targetdoorstate);
|
|
61
|
+
this.service.getCharacteristic(Characteristic.TargetDoorState).updateValue(urlParams.targetdoorstate, undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (urlParams.obstructiondetected != null) {
|
|
66
|
+
var cachedObstructionDetected = this.storage.getItemSync("http-webhook-obstruction-detected-" + this.id);
|
|
67
|
+
if (cachedObstructionDetected === undefined) {
|
|
68
|
+
cachedObstructionDetected = false;
|
|
69
|
+
}
|
|
70
|
+
this.storage.setItemSync("http-webhook-obstruction-detected-" + this.id, urlParams.obstructiondetected);
|
|
71
|
+
if (cachedObstructionDetected !== urlParams.obstructiondetected) {
|
|
72
|
+
if (urlParams.obstructiondetected) {
|
|
73
|
+
this.log(this.name + ": Change Obstruction Detected for garage door opener to '%s'.", urlParams.obstructiondetected);
|
|
74
|
+
this.service.getCharacteristic(Characteristic.ObstructionDetected).updateValue(urlParams.obstructiondetected, undefined, Constants.CONTEXT_FROM_WEBHOOK);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
"success" : true,
|
|
80
|
+
"currentState" : cachedCurrentDoorState,
|
|
81
|
+
"targetState" : cachedTargetDoorState,
|
|
82
|
+
"obstruction" : cachedObstructionDetected
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
HttpWebHookGarageDoorOpenerAccessory.prototype.getTargetDoorState = function(callback) {
|
|
87
|
+
this.log(this.name + ": Getting current Target Door State for '%s'...", this.id);
|
|
88
|
+
var state = this.storage.getItemSync("http-webhook-target-door-state-" + this.id);
|
|
89
|
+
if (state === undefined) {
|
|
90
|
+
state = Characteristic.TargetDoorState.CLOSED;
|
|
91
|
+
}
|
|
92
|
+
callback(null, state);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
HttpWebHookGarageDoorOpenerAccessory.prototype.setTargetDoorState = function(newState, callback, context) {
|
|
96
|
+
this.log(this.name + ": Target Door State for '%s'...", this.id);
|
|
97
|
+
this.storage.setItemSync("http-webhook-target-door-state-" + this.id, newState);
|
|
98
|
+
|
|
99
|
+
var doOpen = newState === Characteristic.TargetDoorState.OPEN;
|
|
100
|
+
var newHomeKitState = doOpen ? Characteristic.CurrentDoorState.OPEN : Characteristic.CurrentDoorState.CLOSED;
|
|
101
|
+
var newHomeKitStateTarget = doOpen ? Characteristic.TargetDoorState.OPEN : Characteristic.TargetDoorState.CLOSED;
|
|
102
|
+
var urlToCall = this.setTargetDoorStateCloseURL;
|
|
103
|
+
var urlMethod = this.setTargetDoorStateCloseMethod;
|
|
104
|
+
var urlBody = this.setTargetDoorStateCloseBody;
|
|
105
|
+
var urlForm = this.setTargetDoorStateCloseForm;
|
|
106
|
+
var urlHeaders = this.setTargetDoorStateCloseHeaders;
|
|
107
|
+
if (doOpen) {
|
|
108
|
+
urlToCall = this.setTargetDoorStateOpenURL;
|
|
109
|
+
urlMethod = this.setTargetDoorStateOpenMethod;
|
|
110
|
+
urlBody = this.setTargetDoorStateOpenBody;
|
|
111
|
+
urlForm = this.setTargetDoorStateOpenForm;
|
|
112
|
+
urlHeaders = this.setTargetDoorStateOpenHeaders;
|
|
113
|
+
}
|
|
114
|
+
Util.callHttpApi(this.log, urlToCall, urlMethod, urlBody, urlForm, urlHeaders, this.rejectUnauthorized, callback, context, (function() {
|
|
115
|
+
this.service.getCharacteristic(Characteristic.TargetDoorState).updateValue(newHomeKitStateTarget, undefined, null);
|
|
116
|
+
this.service.getCharacteristic(Characteristic.CurrentDoorState).updateValue(newHomeKitState, undefined, null);
|
|
117
|
+
}).bind(this));
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
HttpWebHookGarageDoorOpenerAccessory.prototype.getCurrentDoorState = function(callback) {
|
|
121
|
+
this.log(this.name + ": Getting Current Door State for '%s'...", this.id);
|
|
122
|
+
var state = this.storage.getItemSync("http-webhook-current-door-state-" + this.id);
|
|
123
|
+
if (state === undefined) {
|
|
124
|
+
state = Characteristic.CurrentDoorState.CLOSED;
|
|
125
|
+
}
|
|
126
|
+
callback(null, state);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
HttpWebHookGarageDoorOpenerAccessory.prototype.getObstructionDetected = function(callback) {
|
|
130
|
+
this.log(this.name + ": Getting Obstruction Detected for '%s'...", this.id);
|
|
131
|
+
var state = this.storage.getItemSync("http-webhook-obstruction-detected-" + this.id);
|
|
132
|
+
if (state === undefined) {
|
|
133
|
+
state = false;
|
|
134
|
+
}
|
|
135
|
+
callback(null, state);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
HttpWebHookGarageDoorOpenerAccessory.prototype.getServices = function() {
|
|
139
|
+
return [ this.service, this.informationService ];
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
module.exports = HttpWebHookGarageDoorOpenerAccessory;
|