Project tutorial
Use Uber with AWS IoT + Lambda + Arduino Starter Kit

Use Uber with AWS IoT + Lambda + Arduino Starter Kit © MIT

Use Uber without a phone! This AWS IoT connected device allows anyone without a smart phone or different capabilities to request Uber.

  • 3,753 views
  • 0 comments
  • 11 respects

Components and supplies

Apps and online services

About this project

Your Physical Interface with Uber!

Want to see/hear how far the closest Uber is from you? All you have to do is press a button on an AWS IoT connected device. I created this project to allow anyone to have access to Uber even without a smartphone and for those with different capabilities.

Project Overview

Overview

This project sends a button press on an Arduino to AWS IoT over MQTT using the custom "uber" topic. Lambda is waiting for a message payload to match a request. When it matches, the request gets sent to the Uber API, data gets processed, and sent back to the Arduino. The Arduino then beeps the buzzer to represent the estimated time of arrival (ETA) for your Uber request.

Parts

All of the parts that are needed are in the Seeeduino Cloud and Grove Starter Kit for Arduino powered by AWS IoT. I wanted to use only things found in the kit so you can reproduce this project yourself.

  • Grove Button
  • Grove Buzzer
  • Grove Shield
  • Seeeduino Cloud or Arduino Yun

Assembly

  • Connect the Grove Shield to the Seeeduino Cloud (if connecting the shield the Arduino Yun make sure the shield does not touch the Ethernet jack housing)
  • Connect cable from the Grove Buzzer to D2 on the shield
  • Connect cable from the Grove Button to D3 on the shield

Setup Arduino Yun

  • Create Thing on AWS IoT
  • Select Arduino Yun
  • Download new certificate and SDK
  • Place the AWS IoT library in the Arduino library folder
  • Connect Arduino Yun with USB cable
  • Start up Arduino IDE
  • Select Arduino board and com port
  • Edit AWS IoT configuration info to match AWS IoT settings
  • Flash the project code to the Arduino
  • Open serial monitor

Setup Uber

We are going to user Uber's API to request service estimates. A core concept of the Uber API is "product_id". Uber offers many products such as uberX and UberBLACK and these products are not all available in your area. Using the Uber API endpoint for products you can figure out what services are available and their IDs.

GET https://api.uber.com/v1/products?latitude=42.300080&longitude=-71.350349
  • Visit Uber API (https://developer.uber.com)
  • Register app
  • Save CLIENT ID, CLIENT SECRET, and SERVER TOKEN
  • Note "product_id" for the Uber services in your area
  • Note Bearer Token
  • Request Ride Estimate info by sending a start location (lat/long)

Setup Lambda

  • Create new function
  • Handler: index.handler
  • Role: Basic execution role
  • Next
  • Create function
  • Note functionARN (Top Right Corner)
  • Add it to AWS IoT "thing"
  • Click on your Thing's name
  • Click Create a rule
  • Enter a Name and Description
  • Attribute: *
  • Topic filter: uber_request
  • SELECT * FROM 'uber' WHERE command = 'estimate'
  • Under Choose an action select "Insert this message into a code function and execute it (Lambda)"
  • Under Function name select, "UberRequest"
  • Click add action
  • Click Create

Source Code for Lambda Function

var AWS = require('aws-sdk');
var https = require('https');
// Set options for AWS IoT
//   - make sure credentials have AWSIoTDataAccess permissions policy
var CONFIG_AWSIOT = {
  endpoint: 'XXX.iot.us-east-1.amazonaws.com',
  region: 'us-east-1',
  accessKeyId: 'XXX',
  secretAccessKey: 'XXX'
};
// Set options for Uber API  
var CONFIG_UBER = {
  uber_token: "XXX",
  product_id: "XXX",
  start_latitude: 42.300080,
  start_longitude: -71.350349
};
function callUber(event, context) {
  var data =  {
    product_id:      CONFIG_UBER.product_id,
    start_latitude:  CONFIG_UBER.start_latitude,
    start_longitude: CONFIG_UBER.start_longitude
  };
  data = JSON.stringify(data);
  var headers = {
    'Authorization': 'Bearer ' + CONFIG_UBER.uber_token,
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(data)
  };
  var options = {
    host:    'api.uber.com',
    path:    '/v1/requests/estimate',
    method:  'POST',
    headers: headers
  };
  var req = https.request(options, function(res) {
    res.on('data', function (chunk) {
      uberData = JSON.parse(chunk);
      iotdata = new AWS.IotData(CONFIG_AWSIOT);
      params = {
        topic: 'uber_response',
        payload: uberData.pickup_estimate.toString(),
        qos: 0
      };
      iotdata.publish(params, function(err, data) {
        if (err) {
          console.log(err, err.stack);
          context.fail(event); 
        }
        else {
          console.log(data);
          context.succeed(event);
        }
      });
      console.log(chunk.toString());
    });
  });
  req.write(data);
  req.end();
  req.on('error', function(e) {
    context.fail(event); 
  });
}
exports.handler = callUber;

Take it Further

I learned so much by creating this project. I also came up with several new ideas on how to take this project further. Maybe you can use this to create something awesome.

Here are a few of my next steps:

  • Send Philips Hue colors to indicate how close Uber is
  • Interface to other API such as ThingSpeak for data collection and analysis
  • Built IoT gateway for AWS IoT services
  • Build Lambda and SNS alerts
  • Build Lambda and S3 integration

Code

Arduino Yun Pub/Sub to AWS IoTArduino
Publishes button presses (D3) to the "uber" topic and subscribes to "uber_respone" topic to activate the buzzer board (D2).
/*
 * Uber + AWS IoT + Lambda + Arduino
 * 
 * Use an AWS IoT connected Arduino Yun to indicate how far your Uber car
 * is away from you. This project started with the BasicPubSub example by
 * Amazon to interface with AWS IoT.
 * 
 * https://github.com/nothans/Uber-AWS-IoT
 * 
 * Created: January 31, 2016 by Hans Scharler - http://www.nothans.com
 */

// Include AWS IoT
#include <aws_iot_mqtt.h>
#include <aws_iot_version.h>
#include "aws_iot_config.h"

// Setup AWS IoT Client
aws_iot_mqtt_client myClient; // init iot_mqtt_client

// Setup global variables for AWS IoT
char msg[32]; // read-write buffer
int cnt = 0; // loop counts
int rc = -100; // return value placeholder
bool success_connect = false; // whether it is connected

// Create a callback for AWS IoT messages
void msg_callback(char* src, int len) {
  
  Serial.println("CALLBACK:");  
  int i;
  for(i = 0; i < len; i++) {
    Serial.print(src[i]);
  }
  Serial.println("");

  // Get number of beeps
  int n = atoi(src);
  
  // Signal Uber's ETA by beeping the buzzer
  soundBeeps(n, 500, 300);  
  
}

// Define pins for button and buzzer
const int pinButton = 3;
const int pinBuzzer = 2;

void setup() {
  // Configure button pin as a digital input
  pinMode(pinButton, INPUT);

  // Configure buzzer pin as a digital output
  pinMode(pinBuzzer, OUTPUT);
    
  // Start serial for debug / monitoring
  Serial.begin(115200);

  // Wait for serial before AWS IoT setup starts
  while(!Serial);
  //
  char curr_version[80];
  sprintf(curr_version, "AWS IoT SDK Version(dev) %d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
  Serial.println(curr_version);
  // Set up the client
  if((rc = myClient.setup(AWS_IOT_CLIENT_ID)) == 0) {
    // Load user configuration
    if((rc = myClient.config(AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT, AWS_IOT_ROOT_CA_PATH, AWS_IOT_PRIVATE_KEY_PATH, AWS_IOT_CERTIFICATE_PATH)) == 0) {
      // Use default connect: 60 sec for keepalive
      if((rc = myClient.connect()) == 0) {
        success_connect = true;
        // Subscribe to "topic1"
        if((rc = myClient.subscribe("uber_response", 1, msg_callback)) != 0) {
          Serial.println("Subscribe failed!");
          Serial.println(rc);
        }
      }
      else {
        Serial.println("Connect failed!");
        Serial.println(rc);
      }
    }
    else {
      Serial.println("Config failed!");
      Serial.println(rc);
    }
  }
  else {
    Serial.println("Setup failed!");
    Serial.println(rc);
  }
  // Delay to make sure SUBACK is received, delay time could vary according to the server
  delay(2000);  
}

void loop() {

  // Check if button is pressed
  if (digitalRead(pinButton)) {
    publishToAWSIoT();
  }

  if (success_connect) {
 
    // Get a chance to run a callback
    if ((rc = myClient.yield()) != 0) {
      Serial.println("Yield failed!");
      Serial.println(rc);
    }
        
  }
    
  delay(1000);
  
}

int publishToAWSIoT() {
  
  if (success_connect) {
    
    // Send the message "estimate" to the "uber_request" topic
    sprintf(msg, "{\"command\":\"estimate\"}", cnt);
    
    if ((rc = myClient.publish("uber", msg, strlen(msg), 1, false)) != 0) {
      Serial.println("Publish failed!");
      Serial.println(rc);
    }
    
    delay(1000);
    
  }
  
}

void soundBeeps(int beeps, int duration, int wait) {
  
    for (int i = 0; i < beeps; i++) {
      
        digitalWrite(pinBuzzer, HIGH);
        delay(duration);
        digitalWrite(pinBuzzer, LOW);
        delay(wait);
        
    }
    
}
AWS Lambda FunctionJavaScript
This Lambda function is triggered when a message on the "uber" topic matches. The function requests data from the Uber API and replies back to the AWS IoT connected Arduino.
var AWS = require('aws-sdk');
var https = require('https');

// Set options for AWS IoT
//   - make sure credentials have AWSIoTDataAccess permissions policy
var CONFIG_AWSIOT = {
  endpoint: 'XXX.iot.us-east-1.amazonaws.com',
  region: 'us-east-1',
  accessKeyId: 'XXX',
  secretAccessKey: 'XXX'
};

// Set options for Uber API  
var CONFIG_UBER = {
  uber_token: "XXX",
  product_id: "XXX",
  start_latitude: 42.300080,
  start_longitude: -71.350349
};

function callUber(event, context) {
    
  var data =  {
    product_id:      CONFIG_UBER.product_id,
    start_latitude:  CONFIG_UBER.start_latitude,
    start_longitude: CONFIG_UBER.start_longitude
  };
  
  data = JSON.stringify(data);
  
  var headers = {
    'Authorization': 'Bearer ' + CONFIG_UBER.uber_token,
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(data)
  };

  var options = {
    host:    'api.uber.com',
    path:    '/v1/requests/estimate',
    method:  'POST',
    headers: headers
  };

  var req = https.request(options, function(res) {
      
    res.on('data', function (chunk) {
        
      uberData = JSON.parse(chunk);
      
      iotdata = new AWS.IotData(CONFIG_AWSIOT);
  
      params = {
        topic: 'uber_response',
        payload: uberData.pickup_estimate.toString(),
        qos: 0
      };
      
      iotdata.publish(params, function(err, data) {
        if (err) {
          console.log(err, err.stack);
          context.fail(event); 
        }
        else {
          console.log(data);
          context.succeed(event);
        }
      });
  
      console.log(chunk.toString());
    });

  });

  req.write(data);
  req.end();
  
  req.on('error', function(e) {
    context.fail(event); 
  });
  
}

exports.handler = callUber;

Schematics

Arduino Yun and Grove Starter Kit assembly
AWS_IoT_Arduino.fzz

Comments

Similar projects you might like

Plant Monitoring System using AWS IoT

Project tutorial by CJA3D

  • 30,463 views
  • 6 comments
  • 77 respects

IoT Home Security Model

Project showcase by Aaron Kow

  • 53,007 views
  • 41 comments
  • 155 respects

Creating an IoT Dashboard with Xkit, Sigfox & AWS

Project tutorial by Daniel Thomas

  • 3,655 views
  • 0 comments
  • 8 respects

Mini Cloud Monitor With AWS & Arduino

Project tutorial by Marc Plassmeier

  • 4,561 views
  • 0 comments
  • 14 respects

Secure YUN

Project tutorial by Abhishek

  • 1,477 views
  • 1 comment
  • 12 respects
Add projectSign up / Login