Browse code

baseline for strava upload

Louis authored on18/10/2022 22:22:24
Showing5 changed files
... ...
@@ -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
35 85
Binary files a/build/bike_companion.pbw and b/build/bike_companion.pbw differ
... ...
@@ -2,7 +2,9 @@
2 2
   "name": "bike_companion",
3 3
   "author": "ljonget@gmail.com",
4 4
   "version": "1.0.0",
5
-  "keywords": ["pebble-app"],
5
+  "keywords": [
6
+    "pebble-app"
7
+  ],
6 8
   "private": true,
7 9
   "dependencies": {
8 10
     "pebble-clay": "^1.0.0"
... ...
@@ -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: