Reid Carlberg

Connected Devices, salesforce.com & Other Adventures

Read Data from Multiple Arduinos with a Raspberry Pi B+ using I2C and Node.js

1

Last year I wrote about controlling an Arduino using a Raspberry Pi and I2C.  I2C being, of course, a 30+ year old protocol that everybody and their brother still supports.  I tried this again, for reasons I’ll state in the very last sentence of this blog, and it failed. Significantly.

Why? Well, turns out I had forgotten the cardinal rule of I2C.

Link your devices, master and slave, sender and receiver, using a shared ground wire.  Otherwise, you’re going to have a bad time.  Really.

Mmm’k, with that out of the way:

1) The Adafruit tutorial is still the best one I’ve found for enabling I2C on your Raspberry Pi. However, raspi-config now helps you do this under advanced options.  I used the advanced options and then doubled checked everything Adafruit told me to do. (Rule #1: do what Adafruit says.)

2) Add your user to the i2c group.  The command is “sudo adduser pi i2c“. This will make your life easier.  Thank you ABC Electronics.

3) Configure your Arduinos as slave senders.  The example code that comes with the Wire library in the Arduino IDE is perfect for this. Wire ground to ground, SDA to SDA and SCL to SCL. Once you add power to the Arduino, install the slave sender example code and boot your pi, you should be able to see your I2C device using the i2cdetect -y 1 command.  Mine with two Arduinos looks like this:

i2cdetect

My code looks a little different than the slave sender sample, since I have a photocell and a temperature probe on each one.  There’s a fair amount of boiler plate code to read those values, but the fundamental structure is the same as the sample code: configure an I2C address, wait for a request, send a fixed length string in response.

#include <Wire.h> 
#include <OneWire>

// Define analog pin
int sensorPin = 0;
int lightLevel = 0;

int DS18S20_Pin = 2; 
OneWire ds(DS18S20_Pin);  // on digital pin 2

String deviceId = "D001";
int wireId = 4;

String lightLevelString = "";
String output;
int m;
char c[5];
char d[10];

// Setup
void setup() {
 Wire.begin(wireId);
 Wire.onRequest(requestEvent);
 // Init serial
 Serial.begin(9600);
}
 
// Main loop
void loop() {
 
 // Get temperature
 int sensorValue = analogRead(sensorPin);
 
 lightLevel = map(sensorValue, 10, 1000, 1, 100);
 m = sprintf(c, "%03d", lightLevel);
 
  float temperature = getTemp();
  
  dtostrf(temperature, 6, 2, d);

  output = deviceId;
  output.concat("|");
  output.concat(String(c));
  output.concat("|");
  output.concat(String(d));
  
  Serial.println(output);
  
 
 delay(1000);
}

void requestEvent() {
  
  char newOut[16];
  output.toCharArray(newOut, 16);
  
  Wire.write(newOut);
}

float getTemp(){
  //returns the temperature from one DS18S20 in DEG Celsius

  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE); // Read Scratchpad

  
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }
  
  ds.reset_search();
  
  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;
  
  return TemperatureSum;
  
}

4) Install node.js on your rpi, and then use npm to install the i2c library.  You should now be able to read your Arduino via Node.js.  My code declares two devices, both with addresses matching the settings in my Arduino code, and it looks like this:

var i2c = require('i2c');
var address = 0x18;

var device1 = new i2c(address, {device: '/dev/i2c-1'});
device1.setAddress(0x4);

var device2 = new i2c(address, {device: '/dev/i2c-1'});
device2.setAddress(0x6);

var devices = [ device1, device2 ];

function handleTimeout() {
	  setTimeout(function() { handleRead(); }, 1000 );
}

function handleRead() {
  	for (i = 0; i < devices.length; i++) {
		    devices[i].readBytes(null,15, function(err,res) {
			      console.log(res.toString('ascii'));
  		  });
  	}
	  handleTimeout();
}

handleTimeout();

The output is pretty simple — it just prints the data it receives, like so:

i2c-dataexample

My final setup consists of two Arduinos (D001 and D002 in the data) connected to one Raspberry Pi B+.  You’ll notice that the RPi is powering both Arduinos.  (Red is power. Back is ground. Blue is SCL. Yellow is SDA.)  Everything is integrated via the breadboard.

2arduinos1pi

Lessons learned (and remembered):

1) Always connect the grounds.  If you’re not seeing your minimally configured, powered and connected slave-sender device, check the ground first.

2) You can easily power a couple of Arduino’s from the RPi.  Nice.  I wonder how many you can power. I’m sure it depends on what you’re doing.

3) The SDA and SCL wires seem to be pretty flexible. You don’t have to chain them in a particular order as far as I can tell. Just make sure there’s some kind of connection and you’re good to go.

4) Arduinos, with built in analog to digital converters, are a lot less painful (and more reliable) to work with when it comes to reading basic sensors and sharing that data with an app running on the RPi.  My original reason for revisiting this use case was dissatisfaction with reading a photocell directly on the RPi using Python (tutorial) and Arduinos are cheap — $10 at MicroCenter.

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

0

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

Refactoring Visualforce Controllers for Lightning Components

1

You might remember Mo Tester, the package that helps you Experiment Faster on Force.com. I’m tweaking it for some Lightning Component stuff (spoiler alert) and ran into this.  (Posting to the Lightning Newbie Notes too.)

The following code won’t compile. You’ll get a handy Return type does not support AuraEnabled error because — wait for it — the @AuraEnabled annotation doesn’t support PageReference return types.

@AuraEnabled
public PageReference createMoTester1() {
    SmartFactory.FillAllFields = true;
    LAB_Mo_Tester_1__c t = (LAB_Mo_Tester_1__c) 
           SmartFactory.createSObject('LAB_Mo_Tester_1__c');
    insert t;
    return new PageReference('/'+t.id);
}

You need to refactor your Visualforce controller to have two methods, one for your existing code, one for your new Lightning Component.  Also, the @AuraEnabled method needs to be static.

public PageReference createMoTester1() {
    Id myMo = LAB_CreateDataHelper.getNewMoTester1Id();
    return new PageReference('/'+myMo);        
}    

@AuraEnabled
public static Id getNewMoTester1Id() {
    SmartFactory.FillAllFields = true;
    LAB_Mo_Tester_1__c t = (LAB_Mo_Tester_1__c) 
           SmartFactory.createSObject('LAB_Mo_Tester_1__c');
    insert t;  
    return t.id;                
}

Note that in this case, based on the way my test classes are structured, this didn’t affect my code coverage. It was 100% before, it’s 100% after.

Incidentally, not supporting PageReference return types is perfectly logical when you think about it.  PageReferences are a Visualforce thing after all.

Also note that, yes, I’m bewildered by my choice of method names here, too.  Also, the original package doesn’t seem to use this method.  And the test coverage in the package didn’t include coverage for the StandardController and StandardSetController dependent constructors. What was I thinking???

Looking at old (ish) code is fun.

Update 2/23/15 — I did use the button, on the list view.  I just didn’t inspect hard enough.  Phew & Sheesh!mo-tester-button-found

 

Also the method has to be static.  Whoops!

npm install parenting

0

My young son and I (aka The Critter) talk about a lot of things, including the fairly abstract work I do.  I wanted to make it more concrete for him, so, for fun, created a super simple node library which is now, shockingly, available via the esteemed npm and of course on github.

The gist? Well, you put a number of things you might say to your child in as prompts, and can then have the computer say them out loud. It comes with defaults, you can create your own, and it of course has auto mode where it just says one right after the other.

Useful phrase like, Reid, use your napkin.  Reid, clean your room.  Reid, stop doing that.

You get the idea!

It must have connected a little because here you can see him changing the configured name to be that of his sister!

Haven’t tested on a Windows machine.

parenting in action!

 

 

 

Salesforce Lightning Component Newbie Notes

1

Like a lot of you, I recently started down the path of learning Lightning Components. These are my notes and code snippets based on a series of questions I asked as I went through the docs and tutorials. I hope you find them useful.

Salesforce Lightning Component Newbie Notes

This is the first time I’ve used Jekyll and markdown to create a relatively extended blog post.  Pretty convenient!

LEGO Mindstorms: Solve Rubik’s Cube in 90 Seconds

1

If you’re looking for a last minute holiday gift for the burgeoning genius on your list, go get a LEGO Mindstorms EV3 set.  Yes, they’re expensive, but they’re worth it.

Want proof?  Watch this:

Yes, that’s from a single set, and it solves the infamous Rubik’s Cube in about 90 seconds. Amazing, right? Yes, it is. And my kid has been talking about it non-stop since I stayed up a little late to build it on Friday night.

I didn’t design this, I just followed the excellent instructions for Mindcub3r from David Gilday.

So totally worth it.

Simple Salesforce Lightning Connect Example (External Objects)

6

Lightning Connect includes External Data Sources and External Objects.  You can try this in your free developer edition. There’s a nice blog that talks about setting up a more custom data service and covers a bit more about why this is super cool.  Andy Mahood also blogged about this recently, including more details on related lists and Chatter.

Lightning Connect is the new service from Salesforce that lets you bring OData content into your Salesforce org. I was curious how to test it, so I thought I’d share what I found.

Step 1: Locate Sample Data

OData is a protocol for exchanging .. er … data, so it makes sense that you could probably find some sample data to connect to. A bit of the old Google led me to this sample data page where you can click on a tab to see “V2″ sources.

salesforce-sample-odata

When you click on the Northwind sample, you get a bunch of XML (hooray). You’ll want to copy the URL in your browser window at this point.

salesforce-sample-odata-xml

Step 2: Create a new External Data Source

Back in your free developer edition, navigate to Setup > Develop > External Data Sources, and fill in the form as shown in the image. In the Server URL, paste the .. er … server URL you just copied above.

salesforce-external-data-source-new

Important: once you click “Save” you then need to click the button that says “Validate and Sync” before you can move on.

salesfroce-external-data-validate-sync

Once that’s complete, you will be able to select the specific object you’re interested in. For this example, select “Categories” and click on “Sync”.

salesforce-external-data-select

After a moment, you will return to the external data source screen and your external objects related list will look like this — sweet!

salesforce-external-objects-related-list

Step 3: Create a Tab for the External Object

If you click on the “Categories” label in external objects related list, you’re going to see an object definition screen that looks shockingly familiar. Yes, it even includes a “Page Layout” section at the bottom.

salesforce-external-object-definition

Adding this to a tab is super easy. Navigate to Setup > Create > Tabs, and create a new tab for a custom object. That’s it!  Now you can easily navigate to particular records, work with list views, etc — all of the stuff you can easily do with custom objects.

salesforce-external-object-related-list

Step 4: Do a SOQL Query

If you’re like me, you are by now fairly curious about accessing the data in Apex and in a standard SOQL query. Head on over to Workbench. When you login, be sure to login using v32.0. Jump to SOQL queries, and select the “Categories__x” object.

workbench-SOQL

And in the .. er … category of least surprising thing ever, you can see it works!

workbench-soql-results

But what about Apex you say? Yes, also just that easy, as you can demonstrate for yourself using Workbench’s Apex Execute utility.

workbench-apex-execute

Pretty Sweet!

Give it a shot and let me know what you think. @ReidCarlberg

 

 

 

 

Follow

Get every new post delivered to your Inbox.

Join 5,350 other followers

%d bloggers like this: