-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #932 from beaugunderson/withings
Adding the Withings connector (with 2 synclets: scale and pressure)
- Loading branch information
Showing
7 changed files
with
279 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
module.exports = { | ||
handler: function(host, apiKeys, done, req, res) { | ||
var qs = require('querystring'); | ||
var request = require('request'); | ||
var url = require('url'); | ||
var OAlib = require('oauth').OAuth; | ||
|
||
var callbackUrl = host + "auth/withings/auth"; | ||
|
||
var OA = new OAlib('https://oauth.withings.com/account/request_token', | ||
'https://oauth.withings.com/account/access_token', | ||
apiKeys.appKey, | ||
apiKeys.appSecret, | ||
'1.0', | ||
callbackUrl, | ||
'HMAC-SHA1', | ||
null, | ||
{ Accept: '*/*', Connection: 'close' }); | ||
|
||
var qs = url.parse(req.url, true).query; | ||
|
||
// Second phase, after user authorization | ||
if (qs && qs.oauth_token && req.session.token_secret) { | ||
OA.getOAuthAccessToken(qs.oauth_token, req.session.token_secret, qs.oauth_verifier, | ||
function(error, oauth_token, oauth_token_secret) { | ||
if (error || !oauth_token) { | ||
return done(new Error("oauth failed to get access token")); | ||
} | ||
|
||
// Note that we're also grabbing and storing | ||
// the user ID from the queryString | ||
done(null, { | ||
consumerKey: apiKeys.appKey, | ||
consumerSecret: apiKeys.appSecret, | ||
token: oauth_token, | ||
tokenSecret: oauth_token_secret, | ||
userId: qs.userid | ||
}); | ||
}); | ||
|
||
return; | ||
} | ||
|
||
// First phase, initiate user authorization | ||
OA.getOAuthRequestToken({ oauth_callback: callbackUrl }, | ||
function(error, oauth_token, oauth_token_secret, oauth_authorize_url) { | ||
if (error) { | ||
return res.end("failed to get token: " + error); | ||
} | ||
|
||
// Stash the secret | ||
req.session.token_secret = oauth_token_secret; | ||
|
||
res.redirect('https://oauth.withings.com/account/authorize?oauth_token=' + oauth_token + '&oauth_callback=' + callbackUrl); | ||
}); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// node-oauth doesn't provide a method for created signed requests with | ||
// query string parameters instead of Authorization headers, so this is a hack. | ||
function authQueryStringFromUrl(OA, pi, host, url, path) { | ||
var params = OA._prepareParameters(pi.auth.token, pi.auth.tokenSecret, 'HMAC-SHA1', url); | ||
|
||
// Remove the OAuth signature from the parameters (we'll generate it again below) | ||
for (var i in params) { | ||
if (params[i][0] == 'oauth_signature') { | ||
delete params[i]; | ||
|
||
break; | ||
} | ||
} | ||
|
||
// OAuth query string parameters need to be sorted | ||
// alphabetically before the signature is generated. | ||
params = params.sort(function(a, b) { | ||
return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0; | ||
}); | ||
|
||
var output = []; | ||
|
||
// Build the query string | ||
for (var parameter in params) { | ||
output.push(params[parameter][0] + '=' + params[parameter][1]); | ||
} | ||
|
||
// Add the signature of the query string to the end of the query string | ||
output.push('oauth_signature=' + OA._encodeData(OA._getSignature('GET', | ||
'http://' + host + path, output.join('&'), pi.auth.tokenSecret))); | ||
|
||
return '?' + output.join('&'); | ||
} | ||
|
||
exports.deviceSync = function(device, pather, querier, arrayer) { | ||
// pi: process info | ||
return function(pi, cb) { | ||
var OAlib = require('oauth').OAuth; | ||
var OA = new OAlib(null, null, pi.auth.consumerKey, pi.auth.consumerSecret, '1.0', null, 'HMAC-SHA1', null); | ||
var http = require('http'); | ||
|
||
var host = 'wbsapi.withings.net'; | ||
|
||
var url = 'http://' + host + pather(pi) + querier(pi); | ||
|
||
var queryString = authQueryStringFromUrl(OA, pi, host, url, pather(pi)); | ||
|
||
// Setup our own HTTP request since we're using | ||
// query string authorization | ||
var options = { | ||
host: host, | ||
port: 80, | ||
path: pather(pi) + queryString, | ||
headers: { | ||
'Accept': '*/*', | ||
'Connection': 'close' | ||
} | ||
}; | ||
|
||
// Send the request | ||
http.get(options, function(res) { | ||
res.setEncoding('utf8'); | ||
|
||
var data = ''; | ||
|
||
res.on('data', function(chunk) { | ||
data += chunk; | ||
}); | ||
|
||
// Once we've got the full response... | ||
res.on('end', function() { | ||
var js; | ||
|
||
// Try parsing it... | ||
try { | ||
js = JSON.parse(data); | ||
} catch(E) { | ||
return cb(E); | ||
} | ||
|
||
var array = {}; | ||
|
||
array[device] = arrayer(pi, js); | ||
|
||
// And return it using the passed in callback, | ||
// with (optionally) updated auth and config data | ||
cb(null, { | ||
auth: pi.auth, | ||
config: pi.config, | ||
data: array | ||
}); | ||
}); | ||
}); | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"author": "Beau Gunderson <beau@beaugunderson.com>", | ||
"name": "withings", | ||
"description": "Withings", | ||
"version": "0.2.0", | ||
"repository": { | ||
"title": "Withings", | ||
"handle": "withings", | ||
"author": "Beau Gunderson <beau@beaugunderson.com>", | ||
"update": "auto", | ||
"github": "https://github.com/LockerProject/Locker", | ||
"type": "connector", | ||
"static": "false", | ||
"url": "" | ||
}, | ||
"engines": { | ||
"node": ">=0.4.9" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
var MAX_ITEMS = 50; | ||
|
||
exports.sync = require('./lib').deviceSync('pressure', function(pi) { | ||
return '/measure'; | ||
}, function(pi) { | ||
if (!pi.config) { | ||
pi.config = {}; | ||
} | ||
|
||
if (typeof pi.config.pressureStart === 'undefined') { | ||
pi.config.pressureStart = 0; | ||
} | ||
|
||
if (pi.config.pressureStart === 0) { | ||
return '?action=getmeas&devtype=4&limit=' + MAX_ITEMS + '&userid=' + pi.auth.userId; | ||
} | ||
|
||
return '?action=getmeas&devtype=4&limit=' + MAX_ITEMS + '&offset=' + pi.config.pressureStart + '&userid=' + pi.auth.userId; | ||
}, function(pi, js) { | ||
var items; | ||
|
||
if (js.body && js.body.measuregrps) { | ||
items = js.body.measuregrps; | ||
} | ||
|
||
if (!js || !items || items.length === 0) { | ||
pi.config.pressureStart = 0; | ||
pi.config.nextRun = 0; | ||
|
||
return []; | ||
} | ||
|
||
if (items.length < MAX_ITEMS) { | ||
pi.config.pressureStart = 0; | ||
pi.config.nextRun = 0; | ||
} else { | ||
pi.config.pressureStart += MAX_ITEMS; | ||
pi.config.nextRun = -1; | ||
} | ||
|
||
return items; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
var MAX_ITEMS = 50; | ||
|
||
exports.sync = require('./lib').deviceSync('scale', function(pi) { | ||
return '/measure'; | ||
}, function(pi) { | ||
if (!pi.config) { | ||
pi.config = {}; | ||
} | ||
|
||
if (typeof pi.config.scaleStart === 'undefined') { | ||
pi.config.scaleStart = 0; | ||
} | ||
|
||
if (pi.config.scaleStart === 0) { | ||
return '?action=getmeas&devtype=1&limit=' + MAX_ITEMS + '&userid=' + pi.auth.userId; | ||
} | ||
|
||
return '?action=getmeas&devtype=1&limit=' + MAX_ITEMS + '&offset=' + pi.config.scaleStart + '&userid=' + pi.auth.userId; | ||
}, function(pi, js) { | ||
var items; | ||
|
||
if (js.body && js.body.measuregrps) { | ||
items = js.body.measuregrps; | ||
} | ||
|
||
if (!js || !items || items.length === 0) { | ||
pi.config.scaleStart = 0; | ||
pi.config.nextRun = 0; | ||
|
||
return []; | ||
} | ||
|
||
if (items.length < MAX_ITEMS) { | ||
pi.config.scaleStart = 0; | ||
pi.config.nextRun = 0; | ||
} else { | ||
pi.config.scaleStart += MAX_ITEMS; | ||
pi.config.nextRun = -1; | ||
} | ||
|
||
return items; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"mongoId": { | ||
"scale": "grpid", | ||
"pressure": "grpid" | ||
}, | ||
"synclets": [ | ||
{ "name": "scale", "frequency": 43200, "threshold": 0 }, | ||
{ "name": "pressure", "frequency": 43200, "threshold": 0 } | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
var fs = require('fs'); | ||
var auth = JSON.parse(fs.readFileSync("../../Me/withings/me.json")).auth; | ||
|
||
console.error('auth', auth); | ||
|
||
var sync = require(process.argv[2]); | ||
|
||
sync.sync({ auth: auth }, function(e, js){ | ||
console.error('error', e); | ||
|
||
console.error("got js", JSON.stringify(js)); | ||
}); |