Internet of Customers – Bluetooth Presence Detection & Salesforce

[easy-social-share counters=1 total_counter_pos="leftbig"]
Internet of Customers – Bluetooth Presence Detection & Salesforce

In Internet of Customers – “Jarvis” Style Personal Agenda with Arduino, Bluetooth and Salesforce we used an Arduino to scan for Bluetooth MAC addresses, identify a guest and read aloud the tasks for that user. In this post, we will cover the approach & code used within the proof, as well as supply it for download.

Jarvis-YouTube-IOC-IOT-Background-Footer

Overview & Bluetooth Module Challenges
The toughest part of this proof was getting the Bluetooth detection working, as my first efforts were potentially complicated with a bad Bluetooth module. I ended up using a Sparkfun Bluetooth Mate Silver with terrific results. It did require soldering, but it ended up being a pretty straightforward process.

Once the Bluetooth was working, I was able to use some excellent Bluetooth detection sample code from Jan Stevens to listen for Bluetooth IDs. Merging this with some code from our Internet of Customers – Heroku, Arduino and Salesforce.com for Customer Service example, we are easily able to send any matches to a Node.js application to evaluate against Salesforce for guest identification.

Communication Between Systems
The screens below show console output from the Node.js application, showing any data it has received from the Arduino, as well as some response data coming back from Salesforce1 APIs. The Node.js application then uses Web Sockets to communicate to the client dashboard with our greeting UI.

bt-arduno-process

Salesforce Field Setup
This is the easiest part of the proof and adding custom fields in explained here. Our Node.js will need to query fields to see if the ID sent by the Arduino device will match a user’s Bluetooth ID in Salesforce. If so, retrieve the user photo, as well as a speaking voice preference.
Jarvis-Image-2b

Greeting Dashboard
Using Web Sockets, the dashboard is able to respond to the Node.js application to update as needed with a visitor photo and name. When the Node.js application is done with the audio greeting and Tasks, it sends another update to reset the UI.

      
      
      

Arduino Code
This Arduino code combines a Bluetooth scan using code from Jan Stevens, combined with our code from prior proofs connecting the Arduino to Wifi.

/*
Code sample based on the following resources
- Bluetooth Detection http://www.fritz-hut.com/2012/08/26/bluetooth-presence-detection/
- WiFi http://arduino.cc/en/Tutorial/WiFiWebClientRepeating
- HTTP PUT https://www.johnbrunswick.com/2014/01/internet-of-customers-arduino-rfid-http-put-node-js/
 */
#include 
#include 
#include 
#include 

char ssid[] = "xxxxx"; // your network SSID (name)
char key[] = "xxxxx"; // your network key

// Keep track of web connectivity
boolean lastConnected = false;
boolean incomingData = false;
int status = WL_IDLE_STATUS; // the Wifi radio's status
int keyIndex = 0; // your network key Index number

// Take care of advoiding duplicate posts
unsigned long lastConnectionTime = 0;
const unsigned long postingInterval = 10*1000;

// Removing duplicate posts to Node.js service within certain interval
unsigned long lastReadTime = 0;
const unsigned long pollingInterval = 10*1000;

IPAddress server(192,168,1,103);  // numeric IP (no DNS)

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiClient client;
unsigned long lastTime;
unsigned long interval = 10000;

int bluetoothTx = 2;  // TX-O pin of bluetooth mate, Arduino D2
int bluetoothRx = 3;  // RX-I pin of bluetooth mate, Arduino D3

SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

String btid;

void setup()
{
  Serial.begin(9600);  // Begin the serial monitor at 9600bps

  bluetooth.begin(115200);  // The Bluetooth Mate defaults to 115200bps
  bluetooth.print("$");  // Print three times individually
  bluetooth.print("$");
  bluetooth.print("$");  // Enter command mode
  delay(100);  // Short delay, wait for the Mate to send back CMD
  bluetooth.println("U,9600,N");  // Temporarily Change the baudrate to 9600, no parity
  // 115200 can be too fast at times for NewSoftSerial to relay the data reliably
  bluetooth.begin(9600);  // Start bluetooth serial at 9600

  Serial.println("------------------");
  Serial.println("Starting - RFID and WiFi POC Test");

  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while(true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WEP network, SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, keyIndex, key);

    // wait 10 seconds for connection:
    delay(10000);
  }

  Serial.println("Connected to WiFi...");
  Serial.println("------------------");
  Serial.println("");

  printWifiStatus();
}

void loop()
{
    // Get current millis();
    unsigned long currentTime = millis();
    // Check if its already time for our process
    if((currentTime - lastTime) > interval) {
        lastTime = currentTime;
        // Enter command mode
        bluetooth.print("$$$");
                //Wait a bit for the module to respond
        delay(200);
                // Start the inquiry scan
        bluetooth.println("IN,2");
        delay(5000);
        delay(500);
        int h = bluetooth.available();
        if(h >= 42) { // we know there is a bluetooth device
            Serial.println("Someone is near...");
            char *id = readSerial(h);
            char *str;

            while((str = strtok_r(id, "n", &id)) != NULL) {
                    Serial.println(str);

                      // TODO - find better way to deal with null at end of str
                      // variable to assign for later use as string
                      btid = (String)str;
                      btid = btid.substring(0, 19);

                  while (client.available()) {
                    char c = client.read();
                    Serial.write(c);
                  }
                  if (!client.connected() && lastConnected) {
                    Serial.println();
                    Serial.println("disconnecting.");
                    client.stop();
                  }
                  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
                    sendData();
                  }
                  lastConnected = client.connected();
            }
        } else if(h <= 21) { // we know there is no bluetooth device
            Serial.println("No device found");
        }
        bluetooth.println("---");

    }
    clearAll();
}

void clearAll() {
    for(int i = 0; i < bluetooth.available(); i++) {
        bluetooth.read();
    }
}

// a bit hacked...
char* readSerial(int h) {
    char input;
    char buffer[100];
    if (bluetooth.available() > 0) {
        int j = 0;
        for (int i = 0; i < h; i++) { // the id's start at char 21, se we copy from there
            input = (char)bluetooth.read();
            if(i >= 21) {
                buffer[j] = input;
                buffer[j+1] = '';
                j++;
            }
        }
        return buffer;
    } else {
        return "No Data";
    }
}

void sendData() {
  Serial.println("----------------->");
  Serial.println("Trying to send card data to server for card " + btid + "...");

  // if you get a connection, report back via serial:
  // change port info as needed, this was used with a local instance via Heroku command line
  if (client.connect(server, 3001)) {

    Serial.println("Connected to server...");
    String feedData = "n{"mobiledevice" : {"btid" : "" + btid + ""}}";

    Serial.println("Sending: " + feedData + "...");

    client.println("PUT /checkin/ HTTP/1.0");

    client.println("Host: 192.168.1.103");
    client.println("Content-Type: application/json");
    client.println("Content-Length: " + String(feedData.length()));
    client.print("Connection: close");
    client.println();
    client.print(feedData);
    client.println();

    Serial.println("Data has been sent...");
    Serial.println("----------------->");

    delay(2000);

    lastConnectionTime = millis();

    while (client.available() && status == WL_CONNECTED) {
  	if (incomingData == false)
	{
          Serial.println();
	  Serial.println("--- Incoming data Start ---");
	  incomingData = true;
	}
	char c = client.read();
	Serial.write(c);
        client.flush();
        client.stop();
    }

    if (incomingData == true) {
      Serial.println("--- Incoming data End");
      incomingData = false;
    }
    if (status == WL_CONNECTED) {
      Serial.println("--- WiFi connected");
    }
    else {
      Serial.println("--- WiFi not connected");
    }
  }
  else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
    Serial.println("disconnecting.");
    client.stop();
  }

  // Reset Bluetooth ID
  btid = "";
}

void printWifiStatus() {
  // Print the SSID of the network you're attached to:
  Serial.println("------------------");
  Serial.println("WiFi Status...");
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // Print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // Print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("Signal Strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  Serial.println("------------------");
  Serial.println("");
}

Node.js Application
The following is the featured method from our Node.js application that uses the Say.js package to provide the audio that speaks a user’s Tasks. We evaluate if any Tasks exist on the basis of a user account containing a Bluetooth ID that matches one that the Arduino has sent.

...
app.put('/checkin', function(req, res) {
  console.log('PUT received');
  var btid = req.body.mobiledevice.btid;

  console.log("Last guest: " + lastguest);
  console.log("New guest : " + btid)

  // check to see if speech is already in progress
  if (readytospeak == 1)
  {

    if (btid != "001FF3AD6525,380104") {
      guests.push(btid);

      // lock the speaking, so we only address 1 guest at a time
      readytospeak = 0

      console.log("Guests so far - ");
      //console.log(btid);

      guests.forEach(function(entry) {
          console.log("Guest: " + entry);
      });

      var taskspeech = '';
      var greetinghour = '';
      var greetinghour = 'afternoon'; // could be dynamic based on time and SFDC user timezone
      var greetingname = '';
      var speechvoice = '';

      // Get user info for photo
      var quser = "SELECT Id, FirstName, LastName, Profile_Photo__c, Greeting_Voice__c FROM User WHERE Phone_Code__c = '" + btid + "'";

      org.query(quser, oauth, function(err, resp){
        if(!err && resp.records) {
            // get speech defaults used for audio greeting
            greetingname = resp.records[0].FirstName;
            speechvoice = resp.records[0].Greeting_Voice__c;

            io.sockets.emit("proximity", resp.records[0]);

            console.log("greetingname: " + greetingname);
            console.log("speechvoice: " + speechvoice);


            // User the MAC address from the Bluetooth
            var q = "SELECT Id, OwnerId, Description FROM Task WHERE OwnerId IN (SELECT Id FROM User WHERE  Phone_Code__c = '" + btid + "') AND Status = 'Not Started'";

            org.query(q, oauth, function(err, resp){
              if(!err && resp.records) {

                var opentasks = resp.records;

                var say = require('say'),
                colors = require('colors'),
                sys = require('sys');

                var plural = '';
                if (opentasks.length > 1)
                {
                  plural = 's';
                }

                // no callback, fire and forget
                say.speak(speechvoice, "Good " + greetinghour + "  " + greetingname + ". You currently have " + opentasks.length + " task" + plural + ".", function () {

                  var taskcount = 0;

                  opentasks.forEach(function(item) {
                    taskcount += 1;

                    // commas add a pause during the speech
                    taskspeech += "Task " + taskcount + ", " + item.Description + ", ";
                  })

                  // no callback, fire and forget
                  say.speak(speechvoice, taskspeech, function () {
                    // close the welcome photo on the client side
                    io.sockets.emit("closephoto", true);

                    // ready to greet another guest
                    readytospeak = 1;
                  });

                });
              }
            });
        }
      });
    }
  }
  else{
     console.log("Speaking is already in process...");
  }

  res.send({});
});
...

Download Source
Download Source Code from Github

4 Comments

  1. rushabhbadani07 4 years ago

    John would u considering, making a step by step video tutorial for this

  2. SachinAgarwal 3 years ago

    Packers and Movers Dwarka – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers in Dwarka – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers Dwarka Delhi – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers in Dwarka Delhi – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers Dwarka New Delhi – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers Dwarka in New Delhi – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers Dwarka Sector 10 – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers Dwarka Sector 7 – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers Dwarka Sector 23 – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers Dwarka Sector 12 – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers Dwarka Sector 9 – http://getpackers.com/packers-and-movers-dwarka-delhi/
    Packers and Movers Dwarka Sector 8 – http://getpackers.com/packers-and-movers-dwarka-delhi/

  3. SachinAgarwal 3 years ago

    Packers and Movers Gurgaon – http://getpackers.com/packers-and-movers-gurgaon/
    Packers and Movers Gurgaon Charges – http://getpackers.com/packers-and-movers-gurgaon/
    Packers and Movers Gurgaon Rates – http://getpackers.com/packers-and-movers-gurgaon/
    Packers and Movers Gurgaon List – http://getpackers.com/packers-and-movers-gurgaon/
    Local Packers and Movers Gurgaon – http://getpackers.com/packers-and-movers-gurgaon/
    Movers and Packers Gurgaon – http://getpackers.com/packers-and-movers-gurgaon/
    Packers and Movers in Gurgaon – http://getpackers.com/packers-and-movers-gurgaon/
    Movers and Packers in Gurgaon – http://getpackers.com/packers-and-movers-gurgaon/
    Gurgaon Packers and Movers – http://getpackers.com/packers-and-movers-gurgaon/
    Gurgaon Movers and Packers – http://getpackers.com/packers-and-movers-gurgaon/
    Packers and Movers Gurgaon to Bangalore – http://getpackers.com/packers-and-movers-gurgaon/
    Packers and Movers Gurgaon to Pune – http://getpackers.com/packers-and-movers-gurgaon/
    Packers and Movers Gurgaon to Mumbai – http://getpackers.com/packers-and-movers-gurgaon/
    Packers and Movers Gurgaon to Hyderabad – http://getpackers.com/packers-and-movers-gurgaon/
    Packers and Movers Gurgaon to Kolkata – http://getpackers.com/packers-and-movers-gurgaon/
    Packers and Movers Gurgaon to Chennai – http://getpackers.com/packers-and-movers-gurgaon/

Leave a reply

Your email address will not be published. Required fields are marked *

*