| ... | ... |
@@ -1,4 +1,4 @@ |
| 1 |
-STRAVA_API |
|
| 1 |
+/*STRAVA_API |
|
| 2 | 2 |
|
| 3 | 3 |
{
|
| 4 | 4 |
"file": /path/to/file.txt, // {File} The uploaded file.
|
| ... | ... |
@@ -30,4 +30,54 @@ OAuth2.0 strava / pebble |
| 30 | 30 |
GET https://www.strava.com/api/v3/athlete with "Authorization" header ="Bearer XXXXX" XXXXX=access token |
| 31 | 31 |
|
| 32 | 32 |
4b- if yes refresh access token with refresh token get in 2 |
| 33 |
- POST https://www.strava.com/oauth/token?client_id=94880&client_secret=08dc170f0fe38f39dd327bea82a28db4400e6f00&refresh_token=XXXXXXX&grant_type=refresh_token |
|
| 33 |
+ POST https://www.strava.com/oauth/token?client_id=94880&client_secret=8a68d5b79f2fb3e00ad3eaa5025253990fbd6a58&refresh_token=c313d612768db4b12af2782372aa1d9349c265cb&grant_type=refresh_token |
|
| 34 |
+*/ |
|
| 35 |
+ |
|
| 36 |
+gpxfile = b.getGpx(!0) // returned gpxfile is string |
|
| 37 |
+upload(gpxfile) |
|
| 38 |
+ |
|
| 39 |
+function getGpx(t) {
|
|
| 40 |
+ if (0 == points.length) return ""; |
|
| 41 |
+ if (creator = "Ventoo SE", gpxfile = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" creator="' + creator + '" version="1.1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd" xmlns:pb10="http://www.pebblebike.com/GPX/1/0/">\n', itemId = -1, trackNumber = 1, points.length > 0) {
|
|
| 42 |
+ for (gpxfile += "<trk>\n<name>Track #1</name>\n<trkseg>\n", prevTime = -1, i = 0; i < points.length; i++) prevTime > 0 && points[i].t - prevTime > 43200 ? (trackNumber++, gpxfile += "</trkseg>\n</trk>\n<trk>\n<name>Track #" + trackNumber + "</name>\n<trkseg>\n") : prevTime > 0 && points[i].t - prevTime > 7200 && (gpxfile += "</trkseg>\n<trkseg>\n"), d = new Date(1e3 * points[i].t), ti = d.toISOString(), gpxfile += '<trkpt lat="' + points[i].la + '" lon="' + points[i].lo + '">\n <ele>' + points[i].a + "</ele><time>" + ti + "</time>\n", !t && points[i].h || (gpxfile += " <extensions>", t && (gpxfile += "<pb10:accuracy>" + points[i].ac + "</pb10:accuracy>"), points[i].h && (gpxfile += "<gpxtpx:TrackPointExtension>", gpxfile += "<gpxtpx:hr>" + points[i].h + "</gpxtpx:hr>", gpxfile += "</gpxtpx:TrackPointExtension>\n"), gpxfile += "</extensions>\n"), gpxfile += "</trkpt>\n", prevTime = points[i].t; |
|
| 43 |
+ gpxfile += "</trkseg>\n</trk>\n" |
|
| 44 |
+ } |
|
| 45 |
+ return gpxfile += "</gpx>\n", gpxfile |
|
| 46 |
+} |
|
| 47 |
+ |
|
| 48 |
+function upload(gpxfile) {
|
|
| 49 |
+ params = {
|
|
| 50 |
+ url: s, |
|
| 51 |
+ method: "POST", |
|
| 52 |
+ data: { description: "desc", data_type: "gpx" },
|
|
| 53 |
+ files: { file: gpxfile },
|
|
| 54 |
+ authorization: "Bearer " + c |
|
| 55 |
+ callback: function() {
|
|
| 56 |
+ var z = ""; |
|
| 57 |
+ if (r && console.log(e.status + " - " + e.txt), 201 == e.status) z = "Your activity has been created"; |
|
| 58 |
+ else if (400 == e.status) z = "An error has occurred. If you've already uploaded the current activity, please delete it in Strava."; |
|
| 59 |
+ else if (401 == e.status) z = "Error - Unauthorized. Please check your credentials in the settings.", o.setAccessToken("");
|
|
| 60 |
+ else try { response_json = JSON.parse(e.txt), response_json.error ? (r && console.log("error:" + response_json.error), z = response_json.error, o.setAccessToken("")) : response_json.status && (r && console.log("status:" + response_json.status), z = response_json.status) } catch (z) { console.log("Error log, " + z) }
|
|
| 61 |
+ z && Pebble.showSimpleNotificationOnPebble("Ventoo SE - Strava", z)
|
|
| 62 |
+ } |
|
| 63 |
+ } |
|
| 64 |
+ //e[0] = params |
|
| 65 |
+ var XHR = new XMLHttpRequest |
|
| 66 |
+ console.log(e[0].url) |
|
| 67 |
+ XHR.open(e[0].method, e[0].url, !0) |
|
| 68 |
+ var r = Math.random().toString().substr(2); |
|
| 69 |
+ XHR.setRequestHeader("content-type", "multipart/form-data; charset=utf-8; boundary=" + r)
|
|
| 70 |
+ e[0].authorization && XHR.setRequestHeader("Authorization", e[0].authorization);
|
|
| 71 |
+ for (var i in e[0].data) o += "--" + r + '\r\nContent-Disposition: form-data; name="' + i + '"\r\n\r\n' + e[0].data[i] + "\r\n"; |
|
| 72 |
+ for (var i in e[0].files) o += "--" + r + '\r\nContent-Disposition: form-data; name="' + i + '" ; filename=test.gpx\r\n\r\n' + e[0].files[i] + "\r\n"; |
|
| 73 |
+ o += "--" + r + "--\r\n" |
|
| 74 |
+ |
|
| 75 |
+ XHR.onreadystatechange = function() {
|
|
| 76 |
+ try {
|
|
| 77 |
+ 4 == XHR.readyState && (n.status = XHR.status, n.txt = XHR.responseText, n.xml = XHR.responseXML, e[0].callback && e[0].callback()) |
|
| 78 |
+ } catch (t) {
|
|
| 79 |
+ console.error("Error2 loading, ", t)
|
|
| 80 |
+ } |
|
| 81 |
+ } |
|
| 82 |
+ XHR.send(o) |
|
| 83 |
+} |
|
| 34 | 84 |
\ No newline at end of file |
| ... | ... |
@@ -76,12 +76,19 @@ static void prv_up_click_handler(ClickRecognizerRef recognizer, void *context) {
|
| 76 | 76 |
|
| 77 | 77 |
static void prv_down_click_handler(ClickRecognizerRef recognizer, void *context) {
|
| 78 | 78 |
//text_layer_set_text(s_other_text_layer, "Down"); |
| 79 |
+ send_message("exit");
|
|
| 80 |
+} |
|
| 81 |
+ |
|
| 82 |
+static void prv_back_click_handler(ClickRecognizerRef recognizer, void *context) {
|
|
| 83 |
+ //text_layer_set_text(s_other_text_layer, "Down"); |
|
| 84 |
+ //send_message("exit");
|
|
| 79 | 85 |
} |
| 80 | 86 |
|
| 81 | 87 |
static void prv_click_config_provider(void *context) {
|
| 82 | 88 |
window_single_click_subscribe(BUTTON_ID_SELECT, prv_select_click_handler); |
| 83 | 89 |
window_single_click_subscribe(BUTTON_ID_UP, prv_up_click_handler); |
| 84 | 90 |
window_single_click_subscribe(BUTTON_ID_DOWN, prv_down_click_handler); |
| 91 |
+ window_single_click_subscribe(BUTTON_ID_BACK, prv_back_click_handler); |
|
| 85 | 92 |
} |
| 86 | 93 |
|
| 87 | 94 |
static void prv_window_load(Window *window) {
|
| ... | ... |
@@ -254,27 +261,31 @@ static void inbox_received_callback(DictionaryIterator *iter, void *context) {
|
| 254 | 261 |
if(status_tuple) {
|
| 255 | 262 |
memset(s_status,'\0',sizeof(s_status)); |
| 256 | 263 |
strncpy(s_status, status_tuple->value->cstring, 2); |
| 257 |
- APP_LOG(APP_LOG_LEVEL_DEBUG, "status message received : %s",s_status); |
|
| 258 |
- |
|
| 259 |
- // DEBUG concatenate all data received |
|
| 260 |
- memset(s_msg,'\0',sizeof(s_msg)); |
|
| 261 |
- strncpy(s_msg, "Acc. ",5); |
|
| 262 |
- strcat(s_msg, s_accuracy); |
|
| 263 |
- strcat(s_msg, " Alt. "); |
|
| 264 |
- strcat(s_msg, s_altitude); |
|
| 265 |
- strcat(s_msg, "\n Max. "); |
|
| 266 |
- strcat(s_msg, s_max_speed); |
|
| 267 |
- //strcat(s_msg, "\n Lat. "); |
|
| 268 |
- //strcat(s_msg, s_latitude); |
|
| 269 |
- //strcat(s_msg, "\n Long. "); |
|
| 270 |
- //strcat(s_msg, s_longitude); |
|
| 271 |
- //strcat(s_msg, "\n Time. "); |
|
| 272 |
- //strcat(s_msg, s_timestamp); |
|
| 273 |
- |
|
| 274 |
- APP_LOG(APP_LOG_LEVEL_DEBUG, "to display : %s ",s_msg); |
|
| 275 |
- |
|
| 276 |
- text_layer_set_text(s_speed_text_layer, s_speed); |
|
| 277 |
- text_layer_set_text(s_other_text_layer, s_msg); |
|
| 264 |
+ /*if (strcmp(s_status,"KO")== 0){
|
|
| 265 |
+ //find a way to exit |
|
| 266 |
+ }else{*/
|
|
| 267 |
+ APP_LOG(APP_LOG_LEVEL_DEBUG, "status message received : %s",s_status); |
|
| 268 |
+ |
|
| 269 |
+ // DEBUG concatenate all data received |
|
| 270 |
+ memset(s_msg,'\0',sizeof(s_msg)); |
|
| 271 |
+ strncpy(s_msg, "Acc. ",5); |
|
| 272 |
+ strcat(s_msg, s_accuracy); |
|
| 273 |
+ strcat(s_msg, " Alt. "); |
|
| 274 |
+ strcat(s_msg, s_altitude); |
|
| 275 |
+ strcat(s_msg, "\n Max. "); |
|
| 276 |
+ strcat(s_msg, s_max_speed); |
|
| 277 |
+ //strcat(s_msg, "\n Lat. "); |
|
| 278 |
+ //strcat(s_msg, s_latitude); |
|
| 279 |
+ //strcat(s_msg, "\n Long. "); |
|
| 280 |
+ //strcat(s_msg, s_longitude); |
|
| 281 |
+ //strcat(s_msg, "\n Time. "); |
|
| 282 |
+ //strcat(s_msg, s_timestamp); |
|
| 283 |
+ |
|
| 284 |
+ APP_LOG(APP_LOG_LEVEL_DEBUG, "to display : %s ",s_msg); |
|
| 285 |
+ |
|
| 286 |
+ text_layer_set_text(s_speed_text_layer, s_speed); |
|
| 287 |
+ text_layer_set_text(s_other_text_layer, s_msg); |
|
| 288 |
+ // } |
|
| 278 | 289 |
}else{
|
| 279 | 290 |
//APP_LOG(APP_LOG_LEVEL_DEBUG, "not status message... "); |
| 280 | 291 |
} |
| ... | ... |
@@ -322,7 +333,6 @@ static void prv_init(void) {
|
| 322 | 333 |
} |
| 323 | 334 |
|
| 324 | 335 |
static void prv_deinit(void) {
|
| 325 |
- send_message("exit");
|
|
| 326 | 336 |
window_destroy(s_window); |
| 327 | 337 |
} |
| 328 | 338 |
|
| ... | ... |
@@ -2,11 +2,12 @@ var Clay = require('pebble-clay');
|
| 2 | 2 |
var clayConfig = require('./config');
|
| 3 | 3 |
var clay = new Clay(clayConfig); |
| 4 | 4 |
|
| 5 |
+ |
|
| 5 | 6 |
var messageKeys = require('message_keys');
|
| 6 | 7 |
|
| 7 | 8 |
var message; |
| 8 |
-var gpx_to_strava = false; |
|
| 9 |
-var gpx_to_web = true; |
|
| 9 |
+var gpx_to_strava = true; |
|
| 10 |
+var gpx_to_web = false; |
|
| 10 | 11 |
|
| 11 | 12 |
var locationInterval; |
| 12 | 13 |
|
| ... | ... |
@@ -50,7 +51,6 @@ function getLocation() {
|
| 50 | 51 |
} |
| 51 | 52 |
} |
| 52 | 53 |
|
| 53 |
- |
|
| 54 | 54 |
// Calculate the distance from 2 geoloc in degrees. |
| 55 | 55 |
// IMPORTANT : this is a calculation from 2D projection, altitude is not involved |
| 56 | 56 |
// |
| ... | ... |
@@ -142,34 +142,60 @@ function GPXfooterBuilder() {
|
| 142 | 142 |
return ret; |
| 143 | 143 |
} |
| 144 | 144 |
|
| 145 |
+ |
|
| 145 | 146 |
// Send GPX to Strava profile |
| 146 | 147 |
// TODO : get authentication creds from settings |
| 147 | 148 |
function SendToStrava() {
|
| 148 | 149 |
console.log('--- GPX upload to strava');
|
| 149 | 150 |
var GPX = localStorage.getItem("GPX");
|
| 151 |
+ // need to automate oAUTH |
|
| 152 |
+ var bearer = "8a68d5b79f2fb3e00ad3eaa5025253990fbd6a58" |
|
| 153 |
+ params = {
|
|
| 154 |
+ url: s, |
|
| 155 |
+ method: "POST", |
|
| 156 |
+ data: { description: "desc", data_type: "gpx" },
|
|
| 157 |
+ files: { file: gpxfile },
|
|
| 158 |
+ authorization: "Bearer " + bearer, |
|
| 159 |
+ callback: function() {
|
|
| 160 |
+ var message = ""; |
|
| 161 |
+ if (r && console.log(e.status + " - " + e.txt), 201 == e.status) {
|
|
| 162 |
+ message = "Your activity has been created"; |
|
| 163 |
+ } else if (400 == e.status) {
|
|
| 164 |
+ message = "An error has occurred. If you've already uploaded the current activity, please delete it in Strava."; |
|
| 165 |
+ } else if (401 == e.status) {
|
|
| 166 |
+ message = "Error - Unauthorized. Please check your credentials in the settings.", o.setAccessToken("");
|
|
| 167 |
+ } else {
|
|
| 168 |
+ try {
|
|
| 169 |
+ response_json = JSON.parse(e.txt), response_json.error ? (r && console.log("error:" + response_json.error), message = response_json.error, o.setAccessToken("")) : response_json.status && (r && console.log("status:" + response_json.status), z = response_json.status)
|
|
| 170 |
+ } catch (z) {
|
|
| 171 |
+ console.log("Error log, " + z)
|
|
| 172 |
+ } |
|
| 173 |
+ } |
|
| 174 |
+ message && Pebble.showSimpleNotificationOnPebble("Ventoo SE - Strava", message)
|
|
| 175 |
+ } |
|
| 176 |
+ } |
|
| 150 | 177 |
|
| 151 |
- |
|
| 152 |
- /* -------------------- */ |
|
| 153 |
- var array = [GPX]; // an array consisting of a single string |
|
| 154 |
- var blob = new Blob(array, { type: "application/gpx+xml" }); // the blob
|
|
| 155 |
- |
|
| 156 |
- // creating multipart/form-data to be sent |
|
| 178 |
+ // fetch or Blob or Formdata are not implemented in pebblekitJS |
|
| 179 |
+ /*fetch('data:application/gpx+xml;base64,'.btoa(GPX))
|
|
| 180 |
+ .then(function(value) { return value.blob() })
|
|
| 181 |
+ .then( |
|
| 182 |
+ function(value) {
|
|
| 157 | 183 |
var data = new FormData(); |
| 158 |
- data.append("file", blob, "blob.gpx");
|
|
| 159 | 184 |
data.append("name", "test");
|
| 160 |
- data.append("description", "testdesc");
|
|
| 185 |
+ data.append("description", "description");
|
|
| 161 | 186 |
data.append("data_type", "gpx");
|
| 187 |
+ data.append("file", value, "blob.gpx");
|
|
| 162 | 188 |
|
| 163 |
- var url = "https://www.strava.com/api/v3/uploads"; |
|
| 164 | 189 |
var xhr = new XMLHttpRequest(); |
| 190 |
+ var url = "https://www.strava.com/api/v3/uploads"; |
|
| 165 | 191 |
xhr.withCredentials = true; |
| 166 | 192 |
xhr.timeout = 10000; // time in milliseconds |
| 167 | 193 |
|
| 168 | 194 |
xhr.open("POST", url, false);
|
| 169 |
- xhr.setRequestHeader("Authorization", "Bearer d8927033b3996efe1e5a4e62425bc2aff8f635b0");
|
|
| 195 |
+ xhr.setRequestHeader("Authorization", "Bearer 8a68d5b79f2fb3e00ad3eaa5025253990fbd6a58");
|
|
| 170 | 196 |
|
| 171 | 197 |
console.log('------GPX / xhr opened with authorization')
|
| 172 |
- console.log('------array for blob: ' + array)
|
|
| 198 |
+ console.log('------array for blob: ' + [GPX])
|
|
| 173 | 199 |
xhr.onload = function() {
|
| 174 | 200 |
console.log('------xhr onload')
|
| 175 | 201 |
if (xhr.readyState === 4) {
|
| ... | ... |
@@ -185,10 +211,15 @@ function SendToStrava() {
|
| 185 | 211 |
} |
| 186 | 212 |
}; |
| 187 | 213 |
|
| 188 |
- // send with data in body |
|
| 189 | 214 |
xhr.send(data); |
| 215 |
+ }, |
|
| 216 |
+ function(error) {
|
|
| 217 |
+ console.log('error')
|
|
| 218 |
+ } |
|
| 219 |
+ )*/ |
|
| 190 | 220 |
/* -------------------- */ |
| 191 | 221 |
|
| 222 |
+ |
|
| 192 | 223 |
} |
| 193 | 224 |
|
| 194 | 225 |
|
| ... | ... |
@@ -433,6 +464,15 @@ Pebble.addEventListener('appmessage', function(e) {
|
| 433 | 464 |
PostToWeb(); |
| 434 | 465 |
} |
| 435 | 466 |
} |
| 467 |
+ // Send the message |
|
| 468 |
+ var dict = {
|
|
| 469 |
+ 'status': "KO" |
|
| 470 |
+ }; |
|
| 471 |
+ Pebble.sendAppMessage(dict, function() {
|
|
| 472 |
+ console.log('Message sent successfully: ' + JSON.stringify(dict));
|
|
| 473 |
+ }, function(e) {
|
|
| 474 |
+ console.log('Message (' + JSON.stringify(dict) + ') failed: ' + JSON.stringify(e));
|
|
| 475 |
+ }); |
|
| 436 | 476 |
|
| 437 | 477 |
break; |
| 438 | 478 |
default: |