Week 10&11: Network, Communication, Interface and Application Programming

Idea

For my final project, I want to build a simple bike computer that sends my rides to Strava. I started with postman to check if using Strava API is smooth, before implementing POST and GET requests from Arduino. After, I need the user input to authenticate to use Strava. Then, I will send some POST and GET requests to Strava to finish the authentications.

POSTMAN

It is a nice software that allows you to send and receive GET and POST requests, as I was able to explore Strava capabilities with a nice interface. Thus, I was able to use it to upload a GPX file which worked.

Authentication Steps

  1. GET Request - Get Authentication:
    https://www.strava.com/oauth/authorize?client_id=........&redirect_uri=http://localhost&response_type=code&scope=activity:write
  2. Sample Response (from browser URL):
    http://localhost/?state=&code=code&scope=read,activity:write

  3. POST Request - Get Access Token:
    https://www.strava.com/oauth/token?client_id=........&client_secret=client_secret &code=code&grant_type=authorization_code
  4. Sample Response:
    { "token_type": "Bearer", "expires_at": 1702254692, "expires_in": 21315, "refresh_token": "...", "access_token": "...", "athlete": { "id": ID, "username": "ma", "resource_state": 2, "firstname": "..", "lastname": "..", "bio": null, "city": null, "state": null, "country": null, "sex": "F", "premium": false, "summit": false, "created_at": "2022-03-18T05:53:05Z", "updated_at": "2022-06-21T01:24:31Z", "badge_type_id": 0, "weight": 0.0, "profile_medium": "https://lh3.googleusercontent.com/a/ACg8ocKILra9HQW1bjoc9bkjeYSrvsfmTLAtLiLHeY6bb2cvHUU=s96-c", "profile": "https://lh3.googleusercontent.com/a/ACg8ocKILra9HQW1bjoc9bkjeYSrvsfmTLAtLiLHeY6bb2cvHUU=s96-c", "friend": null, "follower": null } }

  5. POST Request - Refresh Token (Your token expires every 6 hours):
    https://www.strava.com/oauth/token?client_id=........&client_secret=client_secret &refresh_token=...&grant_type=refresh_token
  6. Sample Response:
    { "token_type": "Bearer", "access_token": "....", "expires_at": 1702253456, "expires_in": 20793, "refresh_token": "...." }

API Endpoints

cURL Example

                
          curl --location 'https://www.strava.com/api/v3/uploads' \
          --header 'Authorization: Bearer 1314b7933c65c2cb4032214823c1705cf4a3b577' \
          --header 'Cookie: _strava4_session=65d748b9tf1cufe6l6cusg7mf2mdkbtu' \
          --form 'activity_type="walk"' \
          --form 'name="Test Walk"' \
          --form 'description="Test description"' \
          --form 'trainer="0"' \
          --form 'commute="0"' \
          --form 'data_type="gpx"' \
          --form 'file=@"/Users/masarah/Documents/Arduino/Final Project /example.gpx"'
                
              

Sample Response:

                
          {
             "id": 11090510901,
             "id_str": "11090510901",
             "external_id": "example.gpx",
             "error": null,
             "status": "Your activity is still being processed.",
             "activity_id": null
          }
                
              

Check Upload Status

Endpoint: https://www.strava.com/api/v3/uploads/11090510901

                
          curl --location 'https://www.strava.com/api/v3/uploads/11090510901' \
          --header 'Authorization: Bearer 1314b7933c65c2cb4032214823c1705cf4a3b577' \
          --header 'Cookie: _strava4_session=65d748b9tf1cufe6l6cusg7mf2mdkbtu'
                
              

Sample Response:

                
          {
             "id": 11090510901,
             "id_str": "11090510901",
             "external_id": "example.gpx",
             "error": null,
             "status": "Your activity is ready.",
             "activity_id": 10360215181
          }
                
              

Moving to the Pico

Try scanning networks

 
              // Simple WiFi network scanner application
// Released to the public domain in 2022 by Earle F. Philhower, III
#include 

void setup() {
  Serial.begin(115200);
}

const char *macToString(uint8_t mac[6]) {
  static char s[20];
  sprintf(s, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  return s;
}

const char *encToString(uint8_t enc) {
  switch (enc) {
    case ENC_TYPE_NONE: return "NONE";
    case ENC_TYPE_TKIP: return "WPA";
    case ENC_TYPE_CCMP: return "WPA2";
    case ENC_TYPE_AUTO: return "AUTO";
  }
  return "UNKN";
}

void loop() {
  delay(5000);
  Serial.printf("Beginning scan at %lu\n", millis());
  auto cnt = WiFi.scanNetworks();
  if (!cnt) {
    Serial.printf("No networks found\n");
  } else {
    Serial.printf("Found %d networks\n\n", cnt);
    Serial.printf("%32s %5s %17s %2s %4s\n", "SSID", "ENC", "BSSID        ", "CH", "RSSI");
    for (auto i = 0; i < cnt; i++) {
      uint8_t bssid[6];
      WiFi.BSSID(i, bssid);
      Serial.printf("%32s %5s %17s %2d %4ld\n", WiFi.SSID(i), encToString(WiFi.encryptionType(i)), macToString(bssid), WiFi.channel(i), WiFi.RSSI(i));
    }
  }
  Serial.printf("\n--- Sleeping ---\n\n\n");
  delay(5000);
}

            

Control LED through the web server

 
              /*Pi Pico W WiFi Station Demo
  picow-wifi-station.ino
  Use WiFi library to connect Pico W to WiFi in Station mode
 
  DroneBot Workshop 2022
  https://dronebotworkshop.com
*/
 
// Include the WiFi Library
#include 
 
// Replace with your network credentials
const char* ssid = "MasarahHS";
const char* password = "...";
 // Set web server port number to 80
WiFiServer server(80);
 
// Variable to store the HTTP request
String header;
 
// Variable to store onboard LED state
String picoLEDState = "off";
 
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
 
void setup() {
 
  // Start Serial Monitor
  Serial.begin(115200);
 
  // Initialize the LED as an output
  pinMode(LED_BUILTIN, OUTPUT);
 
  // Set LED off
  digitalWrite(LED_BUILTIN, LOW);
 
  // Connect to Wi-Fi network with SSID and password
  WiFi.begin(ssid, password);
 
  // Display progress on Serial monitor
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  // Print local IP address and start web server
  Serial.println("");
  Serial.print("WiFi connected at IP Address ");
  Serial.println(WiFi.localIP());
    // Start Server
  server.begin();
}
 
void loop() {
 
  WiFiClient client = server.available();   // Listen for incoming clients
 
  if (client) {                             // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) {  // loop while the client's connected
      currentTime = millis();
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
 
            // Switch the LED on and off
            if (header.indexOf("GET /led/on") >= 0) {
              Serial.println("LED on");
              picoLEDState = "on";
              digitalWrite(LED_BUILTIN, HIGH);
            } else if (header.indexOf("GET /led/off") >= 0) {
              Serial.println("LED off");
              picoLEDState = "off";
              digitalWrite(LED_BUILTIN, LOW);
            }
 
            // Display the HTML web page
            client.println("");
            client.println("");
            client.println("");
 
            // CSS to style the on/off buttons
            client.println("");
 
            // Web Page Heading
            client.println("

Pico W LED Control

"); // Display current state, and ON/OFF buttons for Onboard LED client.println("

Onboard LED is " + picoLEDState + "

"); // Set buttons if (picoLEDState == "off") { //picoLEDState is off, display the ON button client.println("

"); } else { //picoLEDState is on, display the OFF button client.println("

"); } client.println(""); // The HTTP response ends with another blank line client.println(); // Break out of the while loop break; } else { // if you got a newline, then clear currentLine currentLine = ""; } } else if (c != '\r') { // if you got anything else but a carriage return character, currentLine += c; // add it to the end of the currentLine } } } // Clear the header variable header = ""; // Close the connection client.stop(); Serial.println("Client disconnected."); Serial.println(""); } }

Get user input

Part of my final project, I want to get the user input for Strava identification. Thus, here is my attempt to accept the client ID, the client secret and code, sending them through a GET request to get the access token. That Unfortunately did not work out. Using POSTMAN, I completely forgot that this has more layers of certification and authentications to it. Thus, the connection simply failed. Running out of time as usual, I couldn't find the certificate for Strava and make it work in arduino. In terms of syntax, the code work. For reference, check my final project files.

Link to code

Link to strava header

Assignment Description

Individual Assignments:

  1. design, build, and connect wired or wireless node(s) with network or bus addresses and a local interface

Group Assignment:

  1. send a message between two projects

Would you like to get in touch?

Email me!