Skip to content

Commit b45fc18

Browse files
committed
Fixed request error handling. Request must be aborted if error has occurred
Added option to set a request timeout
1 parent 82dfbe1 commit b45fc18

File tree

3 files changed

+68
-40
lines changed

3 files changed

+68
-40
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,8 @@ History
5959
* Added getStatusValues() method to provide bulk updates optionally including metering values
6060

6161
* 20150416, V0.0.6
62-
* Fixed bug in which resulted on a TypeError if withMetering was set to false
62+
* Fixed bug in request processing which caused a TypeError if withMetering was set to false
63+
64+
* 20150508, V0.0.7
65+
* Fixed request error handling. Request must be aborted if error has occurred
66+
* Added option to set a request timeout

demo.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
var smartplug = require('./index'),
22
options = {
3+
timeout: 10000,
34
name:'edimax',
45
host:'192.168.178.65',
56
username: 'admin',
@@ -9,32 +10,32 @@ var smartplug = require('./index'),
910

1011
smartplug.getDeviceInfo(options).then(function (energy) {
1112
console.log(energy);
12-
}).catch(function(e) {console.log(e)});
13+
}).catch(function(e) {console.log("Request failed: ", e)});
1314

1415
smartplug.getSchedule(options).then(function (schedule) {
1516
console.log(schedule);
16-
}).catch(function(e) {console.log(e)});
17+
}).catch(function(e) {console.log("Request failed: ", e)});
1718

1819
// set switch ON
19-
smartplug.setSwitchState(true, options).catch(function(e) {console.log(e)});
20+
smartplug.setSwitchState(true, options).catch(function(e) {console.log("Request failed: ", e)});
2021

2122
smartplug.getSwitchPower(options).then(function (power) {
2223
console.log("Current switch power", power, "Watts");
23-
}).catch(function(e) {console.log(e)});
24+
}).catch(function(e) {console.log("Request failed: ", e)});
2425

2526
smartplug.getSwitchEnergy(options).then(function (energy) {
2627
console.log(energy);
27-
}).catch(function(e) {console.log(e)});
28+
}).catch(function(e) {console.log("Request failed: ", e)});
2829

2930
smartplug.getStatusValues(true, options).then(function (all) {
3031
console.log(all);
31-
}).catch(function(e) {console.log(e)});
32+
}).catch(function(e) {console.log("Request failed: ", e)});
3233

3334
// set switch OFF
34-
smartplug.setSwitchState(false, options).catch(function(e) {console.log(e)});
35+
smartplug.setSwitchState(false, options).catch(function(e) {console.log("Request failed: ", e)});
3536

3637
// get switch status
3738
smartplug.getSwitchState(options).then(function (state) {
3839
console.log("Switch is", state?"ON":"OFF");
3940
console.log(Date.now() - x, "milliseconds ellapsed")
40-
}).catch(function(e) {console.log(e)});
41+
}).catch(function(e) {console.log("Request failed: ", e)});

index.js

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,26 @@ function consoleDebug() {
2121
console.log.apply(this, arguments)
2222
}
2323

24+
function assignDefaultCommandOptions(options) {
25+
return _.assign({
26+
name: 'edimax'
27+
}, options)
28+
}
29+
2430
function postRequest(command, options) {
2531
var requestOptions = _.assign({
26-
port: 10000,
27-
path: 'smartplug.cgi',
28-
method: 'POST',
29-
headers: {
30-
'Content-Type': 'application/xml',
31-
'Content-Length': command.length
32-
},
33-
name: 'edimax',
34-
username: 'admin',
35-
password: '1234'
36-
}, options);
32+
timeout: 0,
33+
port: 10000,
34+
path: 'smartplug.cgi',
35+
method: 'POST',
36+
headers: {
37+
'Content-Type': 'application/xml',
38+
'Content-Length': command.length
39+
},
40+
username: 'admin',
41+
password: '1234'
42+
}, options),
43+
timeoutOccurred = false;
3744

3845
requestOptions.headers['Authorization'] =
3946
"Basic " + new Buffer(requestOptions.username + ":" + requestOptions.password).toString("base64");
@@ -76,9 +83,17 @@ function postRequest(command, options) {
7683
return resolve(doc);
7784
});
7885
}).on('error', function (error) {
86+
if (timeoutOccurred) {
87+
error = new Error("Request timeout occurred - request aborted");
88+
}
7989
debug('ERROR:' + 'Host ' + requestOptions.host + ' ' + error);
90+
postReq.abort();
8091
return reject(error);
92+
}).on('timeout', function () {
93+
timeoutOccurred = true;
94+
postReq.abort();
8195
});
96+
postReq.setTimeout(requestOptions.timeout);
8297
postReq.write(command);
8398
postReq.end();
8499
});
@@ -89,32 +104,36 @@ function postRequest(command, options) {
89104
//
90105

91106
module.exports.getSwitchState = function (options) {
92-
var commandString = createCommandString(options.name, "get", "<Device.System.Power.State/>");
107+
var commandOptions = assignDefaultCommandOptions(options),
108+
commandString = createCommandString(commandOptions.name, "get", "<Device.System.Power.State/>");
109+
93110
return lastRequest = Promise.settle([lastRequest]).then(function () {
94-
return postRequest(commandString, options).then(function (responseDom) {
111+
return postRequest(commandString, commandOptions).then(function (responseDom) {
95112
return Promise.resolve(
96113
/^ON$/.test(xpath.select("//Device.System.Power.State/text()", responseDom).toString())); // true if on
97114
})
98115
});
99116
};
100117

101118
module.exports.setSwitchState = function (state, options) {
102-
var command = util.format("<Device.System.Power.State>%s</Device.System.Power.State>", state ? "ON" : "OFF"),
103-
commandString = createCommandString(options.name, "setup", command);
119+
var commandOptions = assignDefaultCommandOptions(options),
120+
command = util.format("<Device.System.Power.State>%s</Device.System.Power.State>", state ? "ON" : "OFF"),
121+
commandString = createCommandString(commandOptions.name, "setup", command);
104122

105123
return lastRequest = Promise.settle([lastRequest]).then(function () {
106-
return postRequest(commandString, options).then(function () {
124+
return postRequest(commandString, commandOptions).then(function () {
107125
return Promise.resolve();
108126
})
109127
});
110128
};
111129

112130
module.exports.getSwitchPower = function (options) {
113-
var commandString = createCommandString(options.name, "get",
114-
"<NOW_POWER><Device.System.Power.NowPower/></NOW_POWER>");
131+
var commandOptions = assignDefaultCommandOptions(options),
132+
commandString = createCommandString(commandOptions.name, "get",
133+
"<NOW_POWER><Device.System.Power.NowPower/></NOW_POWER>");
115134

116135
return lastRequest = Promise.settle([lastRequest]).then(function () {
117-
return postRequest(commandString, options).then(function (responseDom) {
136+
return postRequest(commandString, commandOptions).then(function (responseDom) {
118137
return Promise.resolve(
119138
parseFloat(xpath.select("//Device.System.Power.NowPower/text()", responseDom).toString())
120139
);
@@ -123,11 +142,12 @@ module.exports.getSwitchPower = function (options) {
123142
};
124143

125144
module.exports.getSwitchEnergy = function (options) {
126-
var commandString = createCommandString(options.name, "get",
127-
"<NOW_POWER><Device.System.Power.NowEnergy.Day/><Device.System.Power.NowEnergy.Week/><Device.System.Power.NowEnergy.Month/></NOW_POWER>");
145+
var commandOptions = assignDefaultCommandOptions(options),
146+
commandString = createCommandString(commandOptions.name, "get",
147+
"<NOW_POWER><Device.System.Power.NowEnergy.Day/><Device.System.Power.NowEnergy.Week/><Device.System.Power.NowEnergy.Month/></NOW_POWER>");
128148

129149
return lastRequest = Promise.settle([lastRequest]).then(function () {
130-
return postRequest(commandString, options).then(function (responseDom) {
150+
return postRequest(commandString, commandOptions).then(function (responseDom) {
131151
return Promise.resolve({
132152
day: parseFloat(xpath.select("//Device.System.Power.NowEnergy.Day/text()", responseDom).toString()),
133153
week: parseFloat(xpath.select("//Device.System.Power.NowEnergy.Week/text()", responseDom).toString()),
@@ -138,11 +158,12 @@ module.exports.getSwitchEnergy = function (options) {
138158
};
139159

140160
module.exports.getStatusValues = function (withMetering, options) {
141-
var command = withMetering?"<Device.System.Power.State/><NOW_POWER/>":"<Device.System.Power.State/>",
142-
commandString = createCommandString(options.name, "get", command);
161+
var commandOptions = assignDefaultCommandOptions(options),
162+
command = withMetering ? "<Device.System.Power.State/><NOW_POWER/>" : "<Device.System.Power.State/>",
163+
commandString = createCommandString(commandOptions.name, "get", command);
143164

144165
return lastRequest = Promise.settle([lastRequest]).then(function () {
145-
return postRequest(commandString, options).then(function (responseDom) {
166+
return postRequest(commandString, commandOptions).then(function (responseDom) {
146167
var result = {
147168
state: /^ON$/.test(xpath.select("//Device.System.Power.State/text()", responseDom).toString()),
148169
nowPower: 0,
@@ -177,11 +198,12 @@ module.exports.getStatusValues = function (withMetering, options) {
177198
};
178199

179200
module.exports.getSchedule = function (options) {
180-
var commandString = createCommandString(options.name, "get",
181-
"<SCHEDULE></SCHEDULE>");
201+
var commandOptions = assignDefaultCommandOptions(options),
202+
commandString = createCommandString(commandOptions.name, "get",
203+
"<SCHEDULE></SCHEDULE>");
182204

183205
return lastRequest = Promise.settle([lastRequest]).then(function () {
184-
return postRequest(commandString, options).then(function (responseDom) {
206+
return postRequest(commandString, commandOptions).then(function (responseDom) {
185207
var result = {};
186208
for (var x = 0; x <= 6; ++x) {
187209
result[x] = xpath.select("//Device.System.Power.Schedule." + x + ".List/text()", responseDom).toString()
@@ -192,11 +214,12 @@ module.exports.getSchedule = function (options) {
192214
};
193215

194216
module.exports.getDeviceInfo = function (options) {
195-
var commandString = createCommandString(options.name, "get",
196-
"<SYSTEM_INFO><Run.Cus/><Run.Model/><Run.FW.Version/><Run.LAN.Client.MAC.Address/></SYSTEM_INFO>");
217+
var commandOptions = assignDefaultCommandOptions(options),
218+
commandString = createCommandString(commandOptions.name, "get",
219+
"<SYSTEM_INFO><Run.Cus/><Run.Model/><Run.FW.Version/><Run.LAN.Client.MAC.Address/></SYSTEM_INFO>");
197220

198221
return lastRequest = Promise.settle([lastRequest]).then(function () {
199-
return postRequest(commandString, options).then(function (responseDom) {
222+
return postRequest(commandString, commandOptions).then(function (responseDom) {
200223
return Promise.resolve({
201224
vendor: xpath.select("//Run.Cus/text()", responseDom).toString(),
202225
model: xpath.select("//Run.Model/text()", responseDom).toString(),

0 commit comments

Comments
 (0)