Reid Carlberg

Connected Devices, salesforce.com & Other Adventures

Tag Archives: salesforce1

Experiment Faster with Lightning Components & Force.com (Mo Tester Update)

0

Update from 2015-03-06: Mo Tester Octothorpe

TL;DR: Updated Mo Tester, install link on Github Repo.

Back in the day I wrote a post called Experiment Faster on Force.com where I confessed to blatantly stealing an idea from Mr. Steve Molis himself.

It was SteveMo’s idea to have a dev org with a bunch of objects already built, objects with fields of every shape.  My add was to create a package out of it, so that other users could try things out more quickly than if they had to build everything themselves.

Hence: Mo Tester.  Mo Tester is lab equipment for your Developer Edition.  It gives you a pre-defined framework for messing around with many kinds of Force.com goodies, and now includes some basic Lightning Components for your enjoyment.

This update:

  • has an new Visualforce controller (which inspired a post on Refactoring Visualforce Controllers for Lightning Components)
  • includes a Mo Tester Lightning Tab suitable for immediate inclusion in your DE’s mobile navigation
  • demonstrates several Salesforce1 Lightning Component events including (drum roll) a SHOW TOASTER button.

Hopefully this update helps you go faster as you’re discovering what you can do on the platform.

Questions? Comments? Feedback? LMK!

@ReidCarlberg

AngularJS & Remote Actions: The Simplest Possible Visualforce Page

3

The other day, spurred on by Mr. Ward’s Building Salesforce1 Mobile Apps with Visualforce, AngularJS, and Bootstrap, I became curious about whether or not I could mix Remote Actions in with his code, and it turns out I can.  And more than that — it turns out to be pretty sweet!

I’ve included a video demo at the bottom of the post and you can install these pages into your developer edition from this unmanaged package.  Note that once you install these into your org, you’ll want to add them to your Mobile Navigation in order to see the Salesforce1 #awesomesauce.  Code is also on github.

The foundations of Remote Actions are simple.  You create an Apex class that performs the operation you want, and then use a @RemoteAction annotation to expose a particular method to the JavaScript Remoting framework.

global class SampleRemoteActionPageController {
    @RemoteAction
    global static List myContacts() {
        return [select id, name, email from Contact Order By LastModifiedDate DESC LIMIT 200];
    }
}

You then create a simple page that calls that remote action.

<apex:page controller="SampleRemoteActionPageController" docType="html-5.0">
 <apex:stylesheet value="//cdn.jsdelivr.net/webjars/bootstrap-sf1/0.1.0-beta.6/css/bootstrap-namespaced.css"/>
 <apex:includeScript value="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.11/angular.min.js"/>
 
 <script>
 var app = angular.module("ngApp", []); 
 app.controller("ContactCtrl", ["$scope", function($scope) {
   $scope.contacts = [];
 
   $scope.getContacts = function() {
     Visualforce.remoting.Manager.invokeAction(
     '{!$RemoteAction.SampleRemoteActionPageController.myContacts}', 
     function(result, event) {
       $scope.contacts = result;
       $scope.$apply();
     }); 
     }
   }]);
 </script>
 <div class="bootstrap" ng-app="ngApp" ng-controller="ContactCtrl" >
 
 <h1 align="center">Click The Button</h1>
 <button ng-click="getContacts()" class="btn btn-lg btn-default btn-block">Get Contacts</button> 
 
 <p>
 <ul>
 <li id="{{current.Id}}" ng-repeat="current in contacts" ng-class-even="'rowEven'">{{current.Name}}</li>
 </ul>
 </p>
</div>
</apex:page>

I love the simplicity and flexibility I’m seeing here.

Just for fun, I also created a demo using the new Remote Objects functionality that’s still in developer preview.  It also works well in both the desktop browser and Salesforce1 mobile app.  Checkout the video below!

 

Control Your Quadcopter Drone Fleet with Salesforce1

9

Let’s say — hypothetically —  your VP of Drone Fleet Operations just asked you to help her handle drone management, route planning, payload optimization and more. What do you do? Well, there’s a few approaches to tackling the problem. Approach #1 is all about controlling drones using the Salesforce1 Mobile app. That’s what I’m going to talk about today. Note that all of this is done with a free Developer Edition and a little code.

Although I won’t cover it here, there’s also a mildly entertaining yet entirely impractical YouTube artifact documenting my adventures at ThingMonk where together with the excellent Darach Ennis we were able to launch a quadcopter using a coffeepot.

Equipment & Architecture

Let’s start by looking at the equipment you’ll need. The first thing is a quadcopter or two.  I used the Parrot AR Drone 2.0 available at pretty much every retailer worth their weight in salt. The Parrot is great for a lot of reasons, but first and foremost is that it has a great API. Where you have an API, great things are possible, right? Now, the Parrot is also a toy, so you production minded folks will probably want to upgrade to something more robust.

ardrone

The way the AR Drone works out of the box is that it creates a WiFi hotspot. You then connect your controlling device to that AR Drone hotspot and operate it. Parrot sets you up with an app that runs on either an iOS or Android device. I’ve controlled them from both platforms and it works great. The default AR Drone configuration requires one controller per drone, and it requires that controller to be on the WiFi network provided by the drone. If you have two drones, they are isolated from each other by their network connections and there’s no interaction.  

ardrone.standardconfig

In order for this to work with Salesforce, and in order to control multiple drones at the same time, we have to somehow unify these devices, which using the out of the box configuration means the controller needs to bridge multiple networks. My goto local interface box is typically the Raspberry Pi, and, fortunately, the Raspberry Pi is capable of supporting multiple network interfaces, which means it can also handle multiple network addresses. There are a few ways you could configure this, but I chose to use a single Raspberry Pi as a bridge between Salesforce and two other Raspberry Pi’s which connect to the AR Drones.  It looks a little like this:

ARDRone.Salesforce.v2

Now all you need is an app to handle the interface to the AR Drone. There are a lot of great ways to do this, and for this example I have used CylonJS and their ARDrone driver.  (You might remember Cylon JS from the Dreamforce Connected Device Lab.  They do tons of great stuff in the robotics world and have cool libraries for JavaScript, Ruby and Go.)

Control via the Streaming API Pattern

My first approach on this project is to use the familiar Streaming API  Pattern. (See Controlling Philips Hue from Salesforce1 for another example, or get started with a really simple streaming API example.) The Drone Gateway connects to Salesforce, listens to a Streaming API Push Topic and then forwards those instructions to a device as soon as they’re received.

On the Salesforce side of the house, we have to create a simple way to generate listenable data. This is easier than it sounds. The first thing we want is an sObject to store the data in. I’m re-using an existing object pattern I’ve used for other message driven work, I call it “Drone Message.”  The two key pieces of data it stores are the Address and Message. You can see in the screen capture that this one is setting the “land” message to “D2”.

Drone_Message__DRONE-00143___salesforce_com_-_Developer_Edition-2

You can of course use the default UI to create the records, but that then requires you to know addresses and message codes. Since code handles those kind of details better than my brain does, I created a simple Apex class to create these records.

public class DroneController{
    public void droneOneTakeoff() {
        insertMessage('D1','takeoff');
    }

    public void droneOneLand() {
        insertMessage('D1','land');
    }

    public void droneTwoTakeoff() {
		insertMessage('D2', 'takeoff');        
    }

    public void droneTwoLand() {
        insertMessage('D2', 'land');
    }

    public void insertMessage(String address, String message) {
        Drone_Message__c m = new Drone_Message__c();
        m.Address__c = address;
        m.Message__c = message;
        insert m;
    }

}

And now all I need is a little Visualforce code to extend this out to the UI layer. Note that this Visualforce page is tied to the Apex code above using the controller attribute.

<apex:page controller="DroneController" standardStylesheets="false" showHeader="false">
<style>
h1 {
font-family: sans-serif;
}

.large {
font-family: sans-serif;
font-size: 18pt;
}
</style>
<h1>Drone Controller</h1>
<apex:form >
<h1>Drone 1</h1>
<p><apex:commandButton action="{!droneOneTakeoff}" value="Takeoff" styleClass="large" />&nbsp;&nbsp;
<apex:commandButton action="{!droneOneLand}" value="Land" styleClass="large"/></p>

<h1>Drone 2</h1>
<p><apex:commandButton action="{!droneTwoTakeoff}" value="Takeoff" styleClass="large"/>&nbsp;&nbsp;
<apex:commandButton action="{!droneTwoLand}" value="Land" styleClass="large" /></p>

</apex:form>
</apex:page>

Now you need to make this Visualforce page available for mobile apps, create a tab for it and finally customize your mobile navigation options.  These are all just a few clicks, so check out the links if you’ve never done it before — pretty easy. Out in the world of humans, this renders as a very simple page, the same one that you saw in the video clip above.

DroneControllerInterface-one

Now that we have a quick and easy way to create listenable messages, let’s take a quick look at the Drone Gateway that’s doing this listening. This is a pattern I’ve re-used a few times, so you might be familiar with it. The gateway authenticates, begins listening to a Streaming API Push Topic, and then handles whatever it receives.  I chose to write this in Node.js and the code is pretty simple. The connect to Salesforce is detailed in the Philips Hue article, so I’ll just show you how it handles the message. Note the “address” and “message” arguments.

function handleMessage(address, message) {
	console.log("address: " + address);
	console.log("message: " + message);
	if (address == 'D1') {
		if (message == 'takeoff') {
			console.log("in d1 takeoff");
			handleRequest("http://10.0.0.2:1337/start");
		} else if (message == 'land') {
			console.log("in d1 land");
			handleRequest("http://10.0.0.2:1337/stop");
		}
	} else if (address == "D2") {
                if (message == 'takeoff') {
                        console.log("in d2 takeoff");
			handleRequest("http://10.0.0.3:1337/start");
                } else if (message == 'land') {
                        console.log("in d2 land");
			handleRequest("http://10.0.0.3:1337/stop");
                }		
	}
}

Now, you will have no doubt noticed that the above code is doing nothing more than making a call to a webserver. When I was testing, I decided that an http based interface would also be fun, so I created a small server that simply responds to two URLs: start and stop. You can see that these map to the CylonJS commands for “takeoff” and “land”.

http.createServer(function(req,res) {
	if (req.url == "/start") {
		console.log("ready to start");
		copter1.connections['ardrone'].takeoff();
	} else if (req.url == "/stop") {
		console.log("ready to stop");
		copter1.connections['ardrone'].land();
	}
	res.writeHead(200, {'Content-Type': 'text/plain'});
	res.end('Executed');
}).listen(1337, "10.0.0.2");

And there you have it. The start to finish message flow now looks like this:

  1. User presses takeoff on their mobile device.
  2. Salesforce1 inserts a Drone Message object for takeoff.
  3. Streaming API picks up the new records, forwards to listeners.
  4. The Node.js based Drone Gateway catches the new record, and sends it to the right address.
  5. The Node.js based Drone Server sends the specific command to the AR Drone.

Code notes and links:

My command center for the video shoot looks a bit more complicated, but it follows the diagrams above.  Note the three Raspberry Pi’s and two network hubs on the lower left.

Control-Multiple-AR-Drones-from-Salesforce1.jpg

Wrap Up

As you can see from the video, it’s pretty easy to get the drones to follow some simple instructions. The primary challenge with this method is the inherent lag between when an instruction is issued and when it gets to the drone.  This lag depends on a huge number of factors — Internet connection, gateway device performance, Streaming API performance, etc — but the end result is the same.  A drone moving at 5-6 meters per second will be in a completely different place by the time it responds to a delayed command.

An interesting experiment that raises a lot of questions for me.  First and foremost, what is the best way to spread device intelligence out among the components of a system?  Which is to say, what kind of work should Salesforce play in this kind of complicated interaction?  My overall feeling is that this, while interesting, is lower level than truly practical today.

Smoothie Charts, Super Cool Way to Visualize Streaming Data in Salesforce, Mobile App or Otherwise.

1

The other day someone asked, How can I get a near real time view of streaming data in Salesforce? They had a good reason, which I won’t go into here, but the question led me to Smoothie Charts.  And I gotta say, I kinda love ’em.  So I’m going to show you a simple example, then I’m going to show you that example in Salesforce1 and a neat trick I noticed.

You can see Smoothie Charts in action by clicking this fabulous link.

In plain old HTML, you can do something like this:

<html>
<head>
<title>SmoothieCharts Demo</title>

</head>
<body>

<p>Time Series One</p>

<canvas id="timeSeriesOneChart" width="600" height="200"></canvas>
<p>Time Series Two</p>

<canvas id="timeSeriesTwoChart" width="600" height="200"></canvas>

<script src="smoothie.js"></script>
<script type="text/javascript">

//two artificial series of streaming data
var timeSeriesOne = new TimeSeries();
var timeSeriesOneData = [50,70,100,90,75,55,10,50,50,50];
var timeSeriesOneCounter = 0;

var timeSeriesTwo = new TimeSeries();
var timeSeriesTwoData = [50,100,50,0,50,50,50,50,50,50];
var timeSeriesTwoCounter = 0;

setInterval(function() {
console.log(timeSeriesOneData[timeSeriesOneCounter]);
timeSeriesOne.append(new Date().getTime(), timeSeriesOneData[timeSeriesOneCounter]);
timeSeriesOneCounter++;
if (timeSeriesOneCounter == timeSeriesOneData.length) {
timeSeriesOneCounter = 0;
}
},500);

setInterval(function() {
console.log(timeSeriesTwoData[timeSeriesTwoCounter]);
timeSeriesTwo.append(new Date().getTime(), timeSeriesTwoData[timeSeriesTwoCounter]);
timeSeriesTwoCounter++;
if (timeSeriesTwoCounter == timeSeriesTwoData.length) {
timeSeriesTwoCounter = 0;
}
},500);

function createTimelineOne() {
var chart = new SmoothieChart();
chart.addTimeSeries(timeSeriesOne, { strokeStyle: 'rgba(0, 255, 0, 1)', fillStyle: 'rgba(0, 255, 0, 0.2)', lineWidth: 4 });
chart.streamTo(document.getElementById("timeSeriesOneChart"), 500);
}

function createTimelineTwo() {
var chart = new SmoothieChart();
chart.addTimeSeries(timeSeriesTwo, { strokeStyle: 'rgba(0, 255, 0, 1)', fillStyle: 'rgba(0, 255, 0, 0.2)', lineWidth: 4 });
chart.streamTo(document.getElementById("timeSeriesTwoChart"), 500);
}

createTimelineOne();
createTimelineTwo();
</script>

</body>
</html>

Which results in animated version of this:

SmoothieCharts_Demo

This is pretty much what you would expect given their site, so not that interesting yet. Note the calls to “setInterval”.  These loop through an array and just add data to the Smoothie Charts provided “TimeSeries” object every half second or so.

Now, let’s say you do this as a Visualforce page in Salesforce (note that you’ll need to upload smoothie.js as a static resource first).  The code looks pretty similar:

<apex:page docType="html-5.0" standardController="Contact">

<p>Time Series One</p>

<canvas id="timeSeriesOneChart" width="600" height="200"></canvas>
<p>Time Series Two</p>

<canvas id="timeSeriesTwoChart" width="600" height="200"></canvas>

<script src="{!$Resource.LAB_SmoothieCharts}"></script>
<script type="text/javascript">
//two artificial series of streaming data
var timeSeriesOne = new TimeSeries();
var timeSeriesOneData = [50,70,100,90,75,55,10,50,50,50];
var timeSeriesOneCounter = 0;

var timeSeriesTwo = new TimeSeries();
var timeSeriesTwoData = [50,100,50,0,50,50,50,50,50,50];
var timeSeriesTwoCounter = 0;

setInterval(function() {
console.log(timeSeriesOneData[timeSeriesOneCounter]);
timeSeriesOne.append(new Date().getTime(), timeSeriesOneData[timeSeriesOneCounter]);
timeSeriesOneCounter++;
if (timeSeriesOneCounter == timeSeriesOneData.length) {
timeSeriesOneCounter = 0;
}
},500);

setInterval(function() {
console.log(timeSeriesTwoData[timeSeriesTwoCounter]);
timeSeriesTwo.append(new Date().getTime(), timeSeriesTwoData[timeSeriesTwoCounter]);
timeSeriesTwoCounter++;
if (timeSeriesTwoCounter == timeSeriesTwoData.length) {
timeSeriesTwoCounter = 0;
}
},500);

function createTimelineOne() {
var chart = new SmoothieChart();
chart.addTimeSeries(timeSeriesOne, { strokeStyle: 'rgba(0, 255, 0, 1)', fillStyle: 'rgba(0, 255, 0, 0.2)', lineWidth: 4 });
chart.streamTo(document.getElementById("timeSeriesOneChart"), 500);
}

function createTimelineTwo() {
var chart = new SmoothieChart();
chart.addTimeSeries(timeSeriesTwo, { strokeStyle: 'rgba(0, 255, 0, 1)', fillStyle: 'rgba(0, 255, 0, 0.2)', lineWidth: 4 });
chart.streamTo(document.getElementById("timeSeriesTwoChart"), 500);
}

createTimelineOne();
createTimelineTwo();
</script>

</apex:page>

And the basic outcome is predictable as well (note that this is not delivered by Sites, so you see the standard Salesforce UI unlike the fabulous link I mentioned above):

salesforce_com_-_Developer_Edition

However, the astute among you will notice that I declared a “standardController” of “Contact” which means I can now get a page like this with just a few clicks (here’s a more detailed explanation).

Contact__Mr__Tim_Barr___salesforce_com_-_Developer_Edition

So yeah that’s awesome but so ~2009.  Check out this action on Salesforce1. Here’s that same Contact page in the Salesforce1 mobile app, iOS edition (iTunes).

Smoothie Charts in Salesforce 1 Contact Page

And then the really fun part is that when you tap on the smoothie chart you get the full sized version of the page.

image (6)

Which I think is pretty sweet.  And, yes, for the curious, this works great on the Android version of Salesforce1 as well.

The code is available in an unmanaged package suitable for the Developer Edition of your choice.

Control an Arduino with a Raspberry Pi Using Node.js and I2C

8

You might also find this post helpful: Read Data from Multiple Arduinos with a Raspberry Pi B+ using I2C and Node.js

As a software developer, I usually stay away from lower level communication protocols. My logic has historically been: they’re a lot of work, and my time is better spent higher up the stack.

A couple of weeks ago, after suffering through a variety of failures and uncertainty higher up the stack, I decided the only way out was to go at least a little deeper. So I bit the bullet and connected a Raspberry Pi to an Arduino using the I2C protocol, and then was able to control the Arduino using Node.js. This post covers how I did it.

Raspberry-Pi-Wild-Thumper.jpg

My use case was fairly simple.  I decided to drive a Wild Thumper using the Salesforce1 mobile app.  The Wild Thumper is controlled by an Arduino compatible board, aptly named the “Wild Thumper Controller“.  You might remember I had a couple of these with me at the Connected Device Lab this Dreamforce.  In order to communicate with Salesforce, it needs to have some kind of a gateway that can talk to the Internet using HTTPS, which is where the Raspberry Pi comes in.  If you have a different flavor or Arduino sitting around this should still work.

There are a lot of really great technical introductions to I2C (including — gasp — one from 2001), but you don’t really need them to get started.  Keep these two basic ideas in mind:

  • You’re going to work in a Master-Slave configuration.
  • You need to connect three pins.  SDA, SCL and Ground.

That’s it.

Step 1: Slave Configuration on the Arduino compatible Wild Thumper Board is pretty easy.  In fact, you can simply use the “Wire > Slave Receiver” sample code included with the IDE to get started (below). Load this in the Arduino IDE as is, send to your device and then start the serial monitor.  Put it aside.

// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this
// Created 29 March 2006
// This example code is in the public domain.
#include <Wire.h>

void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop()
{
  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  while(1 < Wire.available()) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
}

Step 2: Setting up the Raspberry Pi is a little more difficult, but it’s well documented.  If you are using a standard Raspbian distro, the I2C port is not yet enabled.  Adafruit has an excellent post on enabling the I2C port.  Follow those instructions, then c’mon back.

Step 3: Wire your Raspberry Pi and your Arduino together and make sure the RPi can see the Arduino.  Pinouts on the RPi are a little irritating.  I use the Pi Cobbler.  It gives you a handy, easy to read guide to which pins are where.  If you are connecting directly to the GPIO pins, be sure to consult a pinout digram.

Before you connect everything, your RPi should produce this when you use the i2cdetect command.

Raspberry-Pi-Before-Arduino.png

The basic configuration is really simple.  Master SDA pin to Slave SDA, Master SCL pin to Slave SCL, Master GND pin to Slave GND.  On the Wild Thumper Controller, SDA is A4, SCL is A5 and GND is any pin on the outside edge of the board.  And an Arduino Uno R3, there are special pins for I2C, above the AREF pin, clearly labeled on the back side of the board. In my case, the result looks like this (that’s the Wild Thumper Controller on the right, Pi Cobbler on the left):

Raspberry-Pi-Arduino-I2C-Wiring.jpg

After connected, your RPi should produce this (note that there is now a device on 4).

Raspberry-Pi-Arduino-After-I2C.png

Step 4: Install Node.js on to your Raspberry Pi using this simple link.  If you prefer to be a bit more hands on, you can follow these instructions.  If you prefer to be really hands on, you can install it by compiling from the source, but it will probably take > 2 hours and so far in my experience it’s no different.

Step 5: Install something that lets Node.js talk to the Raspberry Pi’s I2C system.  You should use the I2C library.  There are a couple of others out there, but this is easy and popular.  Now you should be able to do something like this:

var i2c = require('i2c');
var device1 = new i2c(0x18, {device: '/dev/i2c-1', debug: false});
device1.setAddress(0x4);
device1.writeByte(0x2, function(err) { console.log("error"); console.log(err); });

And see a “2” in the Arduino serial port monitor (like so).

Arduino-Serial-Monitor.png

There you have it — the basics of controlling an Arduino using a Raspberry Pi with Node.js and I2C. My original goal was to control the Wild Thumper via the Salesforce1 app.  I was able to accomplish that pretty easily.  Here’s my basic controller for the Thumper, and here’s the Node.js app running on the RPi.  I created a simple UI on the Salesforce1 mobile app (below)  that sends commands to the Thumper using the Streaming API and connects to Salesforce using the excellent nforce.

Salesforce1-Arduino.png

%d bloggers like this: