Logging Rainforest RAVEn/EMU-2 Data to ThingSpeak (node.js on Raspberry Pi)

Last year, I bought a Rainforest EMU-2 energy monitor.  It wirelessly talks via zigbee to the smart energy meter that SCE installed at my house a couple of years ago. Unfortunately, its logging capabilities are rather primitive. All it does is give you a crude bar graph of the current and previous day’s usage. SCE actually has fairly detailed logs on their website, which you can access without buying your own energy monitor, but it’s cumbersome to log into their website and navigate down to the pages. Fortunately, a nice feature of the EMU-2 is that it has a USB port which behaves exactly like the Rainforest RAVEn, so you can read out the data into a computer and log it. I decided to hook up the EMU-2 to a Raspberry Pi, and log the data to ThingSpeak with node.js.

Step 1: Install node.js on Raspberry Pi

Unfortunately, the version of node.js that installs via apt-get on the Adafruit Occidentalis distro that I run on my Raspberry Pi is rather old (v 0.6.19), and won’t work with our code. I had to manually install from the nodejs repository:

wget http://nodejs.org/dist/v0.10.22/node-v0.10.22-linux-arm-pi.tar.gz
tar xzf node-v0.10.22-linux-arm-pi.tar.gz
cp -R node-v0.10.22-linux-arm-pi/bin /usr/local
cp -R node-v0.10.22-linux-arm-pi/lib /usr/local
cp -R node-v0.10.22-linux-arm-pi/share /usr/local
echo export NODE_PATH=/usr/local/lib/node_modules:/usr/local/lib/node_modules/npm/node_modules >> ~/.bashrc
source ~/.bashrc

I’m using node.js v0.10.22 because it works, and that’s the version that I’m using on my Debian development machine. I tried to install the latest, v0.11.11, but ran into all sorts of errors.

Step 2: Install node.js libraries

My RAVEn logging script depends on some libraries, serialportthingspeakclient, and xml2js, which we can install via npm:

npm install -g serialport thingspeakclient xml2js

Step 3: node.js code

The RAVEn XML API is fairly simple. To make things even simpler, I found that stormboy had already written a node.js library to decode it and github: stormboy/node-raven. node-raven reads data from RAVEn and uploads it to an MQTT server, so I had to modify the code to upload to ThingSpeak. Below is my script:

[code language=”java”]
/**
* Reads energy data from a smart meter via a RAVEn RFA-Z106 dongle (http://www.rainforestautomation.com/raven) and uploads to ThingSpeak.
hacked from stormboy’s node-raven https://github.com/stormboy/node-raven
by Sam C. Lin
*/

var serialport = require("serialport"),
ThingSpeakClient = require(‘thingspeakclient’),
xml2js = require(‘xml2js’);

process.on(‘uncaughtException’, function(err) {
// handle the error safely
console.log(err);
});

var TRACE = true;

// RAVEn’s serial port
var ravenSerialPath = ‘/dev/ttyUSB0’;

// thingspeak parameters
var channelId = YOUR-THINGSPEAK-CHANNELID;
var apiKey = ‘YOUR-THINGSPEAK-WRITE-API-KEY’;

var tsclient = new ThingSpeakClient();
tsclient.attachChannel(channelId, { writeKey:apiKey});

// date offset for RAVEn which presents timestamp as seconds since 2000-01-01
var dateOffset = Date.UTC(2000, 0, 1);

var dailyNet = 0;
var dailyNetSentDate = 0;

var Raven = function(serialPath) {
var self = this;

// configure the serial port that the RAVEn USB dongle is on.
this.serialPort = new serialport.SerialPort(serialPath, {
baudrate: 115200,
databits: 8,
stopbits: 1,
parity: ‘none’,
parser: serialport.parsers.readline("\r\n")
});

this.serialPort.on("open", function() {
openHandler(self);
});
};

/**
* Get the connection status between the USB device and the power meter
*/
Raven.prototype.getConnectionStatus = function() {
var queryCommand = "<Command><Name>get_connection_status</Name></Command>\r\n";
this.serialPort.write(queryCommand);
};

/**
* Get information about the device
*/
Raven.prototype.getDeviceInfo = function() {
var queryCommand = "<Command><Name>get_device_info</Name></Command>\r\n";
this.serialPort.write(queryCommand);
};

/**
* Query the amount of energy used or fed-in.
*/
Raven.prototype.getSumEnergy = function() {
var queryCommand = "<Command><Name>get_current_summation_delivered</Name></Command>\r\n";
this.serialPort.write(queryCommand);
};

/**
* Get the power currently being used (or fed-in)
*/
Raven.prototype.getSumPower = function() {
var queryCommand = "<Command><Name>get_instantaneous_demand</Name></Command>\r\n";
this.serialPort.write(queryCommand);
};

Raven.prototype.getMessage = function() {
var queryCommand = "<Command><Name>get_message</Name></Command>\r\n";
this.serialPort.write(queryCommand);
};

Raven.prototype.getTime = function() {
var queryCommand = "<Command><Name>get_time</Name></Command>\r\n";
this.serialPort.write(queryCommand);
};

Raven.prototype.getCurrentPrice = function() {
var queryCommand = "<Command><Name>get_current_price</Name></Command>\r\n";
this.serialPort.write(queryCommand);
};

Raven.prototype.close = function() {
this.serialPort.close();
};

// handle serial port open
function openHandler (self) {
var parser = new xml2js.Parser();
var buffer = ""; // read buffer.

if (TRACE) {
console.log(‘serial device open’);
}

// add serial port data handler
self.serialPort.on(‘data’, function(data) {
buffer += data.toString() + "\r\n"; // append to the read buffer
if ( data.toString().indexOf(‘</’) == 0 ) { // check if last part of XML element.

// try to parse buffer
parser.parseString(buffer, function (err, result) {
if (err) {
console.log("err: " + err);
console.log(‘data received: ‘ + buffer);
}
else if (result.InstantaneousDemand) {
var timestamp = parseInt( result.InstantaneousDemand.TimeStamp );
timestamp = new Date(dateOffset+timestamp*1000);
var demand = parseInt( result.InstantaneousDemand.Demand, 16 );
demand = demand < 0x80000000 ? demand : – ~demand – 1;
if (TRACE) {
console.log("demand: " + timestamp.toLocaleString() + " : " + demand);
}
var tsData = new Object();
tsData = { field1: demand };
tsclient.updateChannel(channelId,tsData);
}
else if (result.CurrentSummationDelivered) {
var timestamp = parseInt( result.CurrentSummationDelivered.TimeStamp );
timestamp = new Date(dateOffset+timestamp*1000);
var used = parseInt( result.CurrentSummationDelivered.SummationDelivered, 16 );
var fedin = parseInt( result.CurrentSummationDelivered.SummationReceived, 16 );
var curDate = timestamp.getDate();
var net = used – fedin;

if (dailyNet == 0) {
dailyNet = net;
dailyNetSentDate = curDate;
}

if (TRACE) {
console.log("sum: " + timestamp.toLocaleString() + " : " + used + " – " + fedin);
}

var tsData = new Object();
tsData = { field2: net,field3: used,field4: fedin};

// only send daily net once a day
if (curDate !== dailyNetSentDate) {
tsData.field5 = net – dailyNet;
dailyNet = net;
dailyNetSentDate = curDate;
}

tsclient.updateChannel(channelId,tsData);

}
else if (result.ConnectionStatus) {
if (TRACE) {
console.log("connection status: " + result.ConnectionStatus.Status);
}
}
else {
if (TRACE) {
console.dir(result); // display data read in
}
}
});
buffer = ""; // reset the read buffer
}
});
}

var raven = Raven(ravenSerialPath);
[/code]

Before you can run the script, you must ravenSerialPath, channelId, and apiKey to match your own configuration. Node that the code contains several getters which I don’t use, because by default, my EMU-2 sends out the data via the USB serial port at regular intervals.

Step 4: ThingSpeak Channel Configuration

Next, you must create a new ThingSpeak channel with 5 fields:
tsraven

Step 5: Run our node.js script

node raven-log.js &

Below are the live data from my ThingSpeak channel: Rainforest RAVEn Logging Demo






I will be updating the code from time to time. You can always get the latest version from github: lincomatic/raven-thingspeak

Logging Nest Thermostat Data: Update 1

I have updated my Nest thermostat data logger. The changes are as follows:

  1. added fan status, heater status, and AC status.
  2. polling interval increased from 15 min to 1 min.
  3. data are pushed to ThingSpeak only if at least one field changes.

The new node.js code:

[code language=”java”]
"option strict";
var util = require(‘util’),
ThingSpeakClient = require(‘thingspeakclient’);
nest = require(‘unofficial-nest-api’); // get from npm

process.on(‘uncaughtException’, function(err) {
// handle the error safely
console.log(err);
});

// nest parameters
var username = ‘YOUR-NEST-LOGIN’;
var password = ‘YOUR NEST PASSWORD’;

// thingspeak parameters
var channelId = YOUR-THINGSPEAK-CHANNEL-ID;
var apiKey = ‘YOUR THINGSPEAK-WRITE-API-KEY’;

// update interval in ms
var updateInterval = 1000*60;

var tsclient = new ThingSpeakClient();
tsclient.attachChannel(channelId, { writeKey:apiKey});

var setTemp = 0;
var curTemp = 0;
var curHum = 0;
var curFanState = -1;
var curHeaterState = -1;
var curACState = -1;

function trimQuotes(s) {
if (!s || s.length === 0) {
return ”;
}
var c = s.charAt(0);
var start = (c === ‘\” || c === ‘"’) ? 1 : 0;
var end = s.length;
c = s.charAt(end – 1);
end -= (c === ‘\” || c === ‘"’) ? 1 : 0;
return s.substring(start, end);
}

function merge(o1, o2) {
o1 = o1 || {};
if (!o2) {
return o1;
}
for (var p in o2) {
o1[p] = o2[p];
}
return o1;
}

function fetchData(data) {
nest.login(username, password, function (err, data) {
if (err) {
console.log(err.message);
//process.exit(1);
return;
}

nest.fetchStatus(function (data) {
for (var deviceId in data.device) {
if (data.device.hasOwnProperty(deviceId)) {
var shared = data.shared[deviceId];
var date = new Date();
var time = date.getFullYear()+’/’+date.getMonth()+’/’+date.getDate()+’-‘+date.getHours()+’:’+date.getMinutes();
var cTemp = nest.ctof(shared.current_temperature);
var sTemp = nest.ctof(shared.target_temperature);
var cHum = data.device[deviceId].current_humidity;
var cFanState = (shared.hvac_fan_state == true) ? 1 : 0;
var cHeaterState = (shared.hvac_heater_state == true) ? 1 : 0;
var cACState = (shared.hvac_ac_state == true) ? 1 : 0;

console.log(util.format("%s %s [%s], cur temp: %d F cur humidity: %d %% set temp: %d fan: %s heat: %s AC: %s",
time,
shared.name, deviceId,
cTemp,
cHum,
sTemp,
cFanState ? ‘on’ : ‘off’,
cHeaterState ? ‘on’ : ‘off’,
cACState ? ‘on’ : ‘off’
));
if ((cTemp !== curTemp) || (cHum !== curHum) ||
(sTemp !== setTemp) || (cFanState !== curFanState) ||
(cHeaterState !== curHeaterState) ||
(cACState !== curACState)) {
var tsData = new Object();
tsData.field1 = cTemp;
tsData.field2 = cHum;
tsData.field3 = sTemp;
tsData.field4 = cFanState;
tsData.field5 = cHeaterState;
tsData.field6 = cACState;
console.log("sending to thingspeak");
tsclient.updateChannel(channelId,tsData);
}
curTemp = cTemp;
curHum = cHum;
setTemp = sTemp;
curFanState = cFanState;
curHeaterState = cHeaterState;
curACState = cACState;
}
}
});
});
}

fetchData();
setInterval(fetchData,updateInterval);
[/code]

The corresponding ThingSpeak Channel also needs to have 3 new fields added to it:

  1. Field 4: Fan State
  2. Field 5: Heater State
  3. Field 6: AC State

I am currently running the demo on a Raspberry Pi. As before, you can view my live channel on ThingSpeak: Nest Logging Demo

I will be updating the code from time to time.  You can always get the latest version from github: lincomatic/nest-thingspeak

Related Articles: Nest

Logging Nest Thermostat Data

I recently had a Nest Thermostat installed at my house for free by my gas company as part of a pilot program that they’re running. It’s a pretty cool device, though I wouldn’t spend $250 to buy one. I like the fact that it’s a lot easier to use than my previous smart thermostat, especially being able to program it from a computer or my smartphone.  One very interesting feature to me is that it tracks the relative humidity of my house. Unfortunately, the Nest app doesn’t let you keep a running log of your data, so I decided to hack together a solution today.

I used node.js to implement a data logger which queries some parameters from my Nest thermostat, and upload it to ThingSpeak at regular intervals. Specifically, my node.js script uploads my Nest’s current temperature, humidity, and the current set temperature to thingspeak every 15 minutes. Below is the node.js script:

[code language=”java”]
"option strict";
var util = require(‘util’),
ThingSpeakClient = require(‘thingspeakclient’);
nest = require(‘unofficial-nest-api’); // get from npm

// nest parameters
var username = ‘YOUR-NEST-USERNAME’;
var password = ‘YOUR-NEST-PASSWORD’;

// thingspeak parameters
var channelId = YOUR-THINGSPEAK-CHANNELID;
var apiKey = ‘YOUR-THINGSPEAK-WRITE-API-KEY’;

// update interval in ms
var updateInterval = 1000*60*15;

var tsclient = new ThingSpeakClient();
tsclient.attachChannel(channelId, { writeKey:apiKey});

function trimQuotes(s) {
if (!s || s.length === 0) {
return ”;
}
var c = s.charAt(0);
var start = (c === ‘\” || c === ‘"’) ? 1 : 0;
var end = s.length;
c = s.charAt(end – 1);
end -= (c === ‘\” || c === ‘"’) ? 1 : 0;
return s.substring(start, end);
}

function merge(o1, o2) {
o1 = o1 || {};
if (!o2) {
return o1;
}
for (var p in o2) {
o1[p] = o2[p];
}
return o1;
}

function fetchData(data) {
nest.login(username, password, function (err, data) {
if (err) {
console.log(err.message);
process.exit(1);
return;
}

nest.fetchStatus(function (data) {
for (var deviceId in data.device) {
if (data.device.hasOwnProperty(deviceId)) {
var shared = data.shared[deviceId];
var date = new Date();
var time = date.getFullYear()+’/’+date.getMonth()+’/’+date.getDate()+’-‘+date.getHours()+’:’+date.getMinutes();

console.log(util.format("%s %s [%s], Current temp: %d F Current Humidity: %d %% Target temp: %d",
time,
shared.name, deviceId,

nest.ctof(shared.current_temperature),
data.device[deviceId].current_humidity,

nest.ctof(shared.target_temperature)));

var fields = { field1: nest.ctof(shared.current_temperature),field2: data.device[deviceId].current_humidity, field3: nest.ctof(shared.target_temperature)};
tsclient.updateChannel(channelId,fields);
}
}
});
});
}

fetchData();
setInterval(fetchData,updateInterval);
[/code]

In order to run my node.js script, you need to first use npm to install unofficial-nest-api and thingspeakclient. My script is actually just a hacked up version of the example that comes with unofficial-nest-api.

Note that you must first update the initialization of username and password with your Nest.com login credentials.

Also, you need to enter your channel id and write api key from thingspeak.com. Below are my thingspeak channel settings:

channel

You can view my channel live on thingspeak here: Nest Logging Demo

channelview

LeafCAN v2 Firmware in Alpha Test

I have been working on v2 of the LeafCAN firmware, which adds a whole slew of new screens, selectable via a rotary encoder.  The rotary encoder is connected to the AD0/1/2 pins on the expansion header of the LeafCAN V2 hardware.  The code is currently in alpha testing, and is available in the development branch of the LeafCAN github repository.  Be aware that the development branch is for my bleeding edge code, and at any time, the code there may be broken, as I continually checkpoint my code.  I will move it to the master branch when it’s ready to be released.

While I was developing the LeafCAN v2 firmware, I received a pleasant surprise in the mail from Barbouri (GregC) of the MyNissanLeaf forum.  He designed a PCB with 16×2 OLED display + RGB Led Rotary Encoder support,

v2o

and sent me a completely assembled and tested rig.  I immediately added support for this new hardware variant into my working LeafCAN v2 firmware code.  The RGB knob is cool:

encoderled

but I am still pondering how best to use it. Currently, I have it blue when the car is idle, red when it’s consuming power, and green during regen.
Below is an overview of LeafCAN v2Alpha3. The various screens are selected by rotating the encoder knob. Some of the screens have different modes, selected via a press of the encoder knob. The first screen is the familiar info screen from LeafCAN v1.3:

mainscreen

The top line from left to right is: kWh remaining/gids/fixed fuel bars, and the bottom line is: pack voltage/SOC%/instantaneous kW. The next screen is an idea lifted from Turbo3’s WattsLeft, the DTE (distance to event) screen:

dtel

The top line shows various miles/kWh values, 2.0/3.0/4.0/5.0/6.0, and bottom line shows the distance in miles to the event, in this case, Low Battery.  Pressing the encoder button switches it to miles until Very Low Battery:

dtev

and pressing the button a third time shows miles until Turtle:

dtet

Thanks to a breakthrough in active can sampling, spearheaded by GregH and TickTock, I was able to implement the following new screens. The first one has on the top line, High Precision State of Charge (SOC)%.  The bottom line shows State of Charge (Ah), and possibly a Battery Health %.

soccap

The next screen shows the 4 battery pack temperature sensors:

batttemp

The units are selectable between Celcius and Fahrenheit with a press of the button. Finally, the last screen shows the minimum and maximum cell-pair voltages in mV, as well as their difference:

cellvolt

When an OLED is installed, the display now blanks after 5 sec of inactivity on the CAN bus. Pressing and holding the knob for a second wakes the display up for 5 sec.  When an LCD is installed, the press/hold turns on the backlight for 5 sec, instead.

I will be working towards finishing LeafCAN v2.0 in the coming weeks, and will announce its release here.

Barbouri and I are also collaborating on a dual-CAN bus version of the LeafCAN hardware, which will be able to monitor the Car-CAN as well as the EV-CAN on the Nissan Leaf. This will open up access to various information which is accessible only via the Car-CAN, such as friction brake actuation, steering angle, etc.

I would also like to point out that GregH has yet another cool Leaf CAN bus dash display in the works (only $80) that is worth checking out. Also, TickTock and garygid are working on the very fancy dual-touchscreen open-source CANary Project. Turbo3 has also figured out how to extract data from the Leaf Car-CAN using a cheap ELM-327 clone dongle and an Android phone. There is currently a flurry of CAN bus hacking on the Leaf.

UCTronics 3.2″ TFT LCD Arduino Shield with Touchscreen

Updated 2014-03-14

I’ve been looking for a way to add a touchscreen UI to my projects.  To this end, I purchased a UCTronics 3.2″ TFT LCD Arduino Shield.  Most of the cheap TFT touchscreens that I found need about 38 pins, and therefore, need to interface with an Arduino Mega.  What makes this UCTronics shield unique is that it uses an onboard latch to convert the onboard SSD1289 TFT driver data bus from 16-bits to 8-bits.  This allows it to connect to an Arduino Duemilanove or UNO.  The board I received is a RevB board, and it looks somewhat different from the board pictured in the UCTronics product description.  The resistive touch panel on top of the TFT very similar to the touch panel used in the Nintendo DS.  Below is the board running UTFT’s demo (UTFT_Demo_320x240):

front

When I purchased this display, I had to use a specially modified version of UTFT downloaded from UCTronics: 3inch2_RevB.zip. This is because at the time, UTFT only supported the SSD1289 in 16-bit mode. However, as of 2014/14/03, the shield now works with the official UTFT distribution. The key is to supply the correct parameters to the UTFT constructor:

[code lang=”c”]

UTFT myGLCD(SSD1289_8,A1,A2,A0,A3);

[/code]

SSD1289_8 specifies that we’re using an SSD1289 controller in 8-bit mode. The rest of the parameters are the pin assignments.

When compiling for an Arduino Duemilanove or UNO, the IDE will complain that the sketch is too big, unless you comment out all of the #define DISABLE_xxx except for #define DISABLE_SSD1289 in UTFT’s memorysaver.h.

While UCTronics’ version of UTFT comes preconfigured, it is based on an older version of UTFT, which is slower. On my Duemilanove, the UTFT_Demo_320x240 sketch takes 57.7 sec to execute with UCTronics’ UTFT, and 48.6 sec with the official UTFT library.  This is mainly because the latest UTFT has a new function called _fast_fill_8(), which speeds up certain fills. However, the sketches built with the newer UTFT library are bigger. With UCTronics’ UTFT, UTFT_Demo_320x240 compiles to 27248 bytes, and 30092 bytes with official UTFT.

Here is a bottom view of the shield:

shield

At right is the integrated micro SD card reader, which is handy for storing bitmap data to load into the screen.

UCTronics supplies ArduCAM_Touch to support the touchscreen. However, I decided to just use UTouch, instead. Below is the UTouch_ButtonTest example sketch:

btndemo

To use UTouch, you must configure the following lines in the sketch:

[code lang=”c”]
UTFT myGLCD(SSD1289_8,A1,A2,A0,A3);
UTouch myTouch(13,10,11,12,9);
[/code]

I was able to operate the buttons by pressing firmly with my fingers. Note that the touchscreen is resistive, not capacitive, so it works by pressure. A stylus gives you considerably more control. The touchscreen is very similar to the one found in a Nintendo DS.

At first, I was disappointed by the bitmap display.  This is the output of the UTFT_Read_BMP demo sketch supplied by UCTronics:

bmp

There is severe quantization of the colors. This is the way due to the way that UCTronics implemented the UTFT::dispBitmap() function in their modified UTFT library. I wrote my own function, dispRaw(), to instead display .raw files generated by UTFT’s ImageConverter 565:

[code language=”c”]
// display a raw bitmap that was processed with ImageConverter565

#include <UTFT.h>
#include <SD.h>
#include <Wire.h>

#define SD_CS 8

//UTFT(byte model, int RS, int WR,int CS,int RD)
UTFT myGLCD(SSD1289_8,A1,A2,A0,A3);

void dispRaw(UTFT *utft,File inFile)
{
char VH,VL;
int i,j = 0;
cbi(utft->P_CS, utft->B_CS);
for(i = 0; i < 320; i++)
for(j = 0; j < 240; j++) {
VL = inFile.read();
VH = inFile.read();
utft->LCD_Write_DATA(VL,VH);
}
sbi(utft->P_CS, utft->B_CS);
utft->clrXY();
}

void setup()
{
myGLCD.InitLCD();
if (SD.begin(SD_CS))
{
char VH,VL;
File inFile;
inFile = SD.open("ade.raw",FILE_READ);
if (! inFile)
{
while (1); //if file does not exsit, stop here.
}
dispRaw(&myGLCD,inFile);
inFile.close();
}
}

void loop(){}
[/code]

The output looks a lot better:

ade

The display is actually much higher quality than the photo above.  The photo contains screening and moire patterns that you don’t see with the naked eye.  To create a RAW file, first create a 240×320 pixel jpg,png, or GIF file.  Run it through either imageconverter565.exe or the online ImageConverter 565 make sure to select Convert to .raw file and Target Platform Arduino (AVR). Copy it to a FAT-formatted uSD card, and insert it into the uSD slot.

It takes about 6 seconds to load a fullscreen RAW file. I’m think the bottleneck is the reading of the data from the SD card. Clearing the screen takes almost 1 second. The speed is acceptable when running UTFT_Demo_240x320.  This is board is no speed demon, but the speed seems adequate for implementing a graphic touchscreen control panel. If you need a fast display, look elsewhere.

Resources:

User Guide
UCTronics Customized UTFT library

UTFT
UTouch

Build a Bluetooth Low Energy (BLE) Controlled RGB LED

I have been wanting to play with my RedBearLab BLE Shield for some time, but have been too busy. This weekend, I finally was able to allocate some time to experiment with it. I decided to do something relatively easy as my first project, so as to familiarize myself with the Bluetooth API’s on both the Arduino and the host side. Wirelessly controlling an RGB LED seemed like something fun to do.  RedBearLab has some example programs for Mac OSX and iOS in their BLE SDK.  I decided to start with OSX, since the compiler and SDK are a free download from Apple.

One nice thing about BLE is that you can write iOS apps that talk to it without going through Apple’s expensive MFA program.  Apple is being asinine, as usual, and decided not to support the RFCOMM profile, which allows older versions of Bluetooth to emulate serial ports, and talk to arbitrary devices.  However, they still force you to pay them $99 per year (yes, per year, not a one-time fee) for the *privilege* of being able to run your own iOS apps on an actual device.  Annoying and evil…

While recent Apple computers have Bluetooth 4.0 support built-in, I have an older Mac Book Pro from 2008.  I bought a cheap CSR BT 4.0 dongle on eBay for <$10.

My Mac is running OSX Mountain Lion, but I was not able to get it working at first, even though I followed the hack described at: https://discussions.apple.com/thread/2265096?start=0&tstart=0. (Note: I deleted the bcdDevice key, rather than updating it as described in the article).  Then I noticed that Apple wanted to install an OSX update.  Once I updated to OSX 10.7.5, the dongle started working properly.  What’s strange is, with the update, I found that there is actually a kext which is configured to directly support my dongle (USB VID = 0x0a12, PID = 0x0001) straight out of the box, but for some strange reason, OSX was detecting it as a Broadcom device, rather than Cambridge Silicon Radio.  While the dongle is working now with the hack, it is a bit flaky on my Mac, and sometimes can’t talk to the BLE Shield, unless I unplug/plug it in or retry several times.  On the other hand, it works flawlessly on my Windows 8 machine.  If anyone knows of a cheap and reliable BT 4.0 dongle for OSX, please leave a comment below.  FYI, when you plug in the BT 4.0 dongle, OSX automatically disables the built-in Bluetooth controller.

Schematic:

I used a common-cathode RGB LED.  Here is the schematic:

 

 

The brightness of each color channel is controlled via PWM, using a value from 0-255.  The BLE Shield uses pins D8 and D9 for communication.  My Arduino Duemilanove has 6 PWM pins: D11, D10, D9, D6, D5, and D3.  Therefore, I decided to use D6=red, D5=green, and D3=blue. I wired it up on a mini protoboard.  To diffuse the light, I drilled a small hole into a Ping-Pong ball, and attached it to the LED.  Here is my test rig:

 

 

I have uploaded all of the code for this project to github: https://github.com/lincomatic/BleRgbLed

Arduino Sketch:

The Arduino code for this project is in BleRgbLed.ino.  Before you can compile the sketch, you must install the BLE Arduino library.  Simply unzip libBLEShield_v1.0.zip into <arduinosketchbook>/libraries.  You will have two subfolders, BLE/ and BluetoothLowEnergy/.

To maintain communication integrity between the host and the Arduino, I decided to implement a simple 5-byte packet format:

<sync byte><red><green><blue><checksum>

where

 <sync byte> = 0xA5

and

<checksum> = <red> XOR <green> XOR <blue>

This way, if the signal drops out or some packets get corrupted, the Arduino can reject bad data, and easily regain sync.

OSX Cocoa App:

The Mac OSX app is very straightforward, using 3 sliders, one for each color, to control the LED:

As a template, I used RedBearLab’s SimpleControl_Mac example, which is included in their BLE SDK.  To compile the app, your Mac must be running OSX 10.7.2+, and you must use XCode 4.2+. To compile an OSX or iOS app that talks to the BLE shield, you must add two frameworks to your project:  1) BLE_Framework from RedBearLab’s SDK and 2) IOBluetooth.framework from Apple’s SDK.

It would be very straightforward to port the app to iOS, using the SimpleControl_IOS sample as a template, but I haven’t done it yet, because my Apple Developer license expired, and I don’t want to spend another $99 for a new one.  It is supposedly possible to run it on your Mac via the iOS Simulator without a developer license, but I wasn’t able to get the simulator to connect to the BLE shield through my BT4.0 dongle.  iPhone 4S/5 and late model iPads have BLE built-in.  I believe you need to be running iOS 5.1+ to use BLE API’s.

Here is what it looks like in a darkened room.  It’s bright enough to make a nice night light. It looks a bit like an Ambient Orb, and with a bit of extra coding, could actually behave like one. With some transistors to drive more current, you could drive RGB LED strips, and make multicolored under-counter kitchen lighting.

I think it would be cool to use the LED as a notifier for SMS messages, voice mail, etc for an iPhone, but I am not yet sure whether or not the proper API’s are available.

I am more comfortable programming Microsoft Windows apps… if anyone has any good examples for getting started with BLE communication API’s under Windows, please leave a comment below.

One of my goals is to build wirelessly controlled RGB LED goggles for photic brain stimulation – once I get this working, I will post a blog entry.

Code Download: https://github.com/lincomatic/BleRgbLed

Previous Post: RedBearLab BLE Shield – First Look

LiquidTWI2 v1.1.0 Released

For the Adafruit RGB LCD Shield (MCP23017), I changed the GPIO writing from 16-bit to 8-bits. This increased the library size by 14 bytes, but it’s well worth it, because writing a 47-character string has sped up from 99ms to 76ms on my Arduino Duemilanove – that’s about a 25% increase!  This is vs Adafruit’s RGB LCD library, which is 1.4K bigger, and takes 322ms.

Download: LiquidTWI2

Related Post: LiquidTWI2 – A Lean, High Performance I2C LCD Library for Arduino

LiquidTWI2 – A Lean, High Performance I2C LCD Library for Arduino

I have released LiquidTWI2, a lean, high speed I2C LCD Library for Arduino. This library is an extension of the great work done by FalconFour on his LiquidTWI library.  Notable additions to LiquidTWI:

LiquidTWI2 also supports the Adafruit I2c Backpack (MCP23008-based) in I2C mode.  The library is a drop-in replacement for both the Adafruit LiquidCrystal Library (for the I2C backpack) and the Adafruit RGB LCD Shield Library.  By replacing either of Adafruit’s libraries with LiquidTWI2, memory use will decrease, and writing to the LCD will become blazingly fast.

Installation:

  1. download LiquidTWI2 from github.
  2. copy the LiquidTWI2 folder to <arduinosketchbook>/libraries/LiquidTWI2

Usage:

I2C Backpack or compatible MCP23008-based module

#include <Wire.h>
#include <LiquidTWI2.h>
LiquidTWI2 lcd(0); // 0 = i2c address
void setup() {
lcd.setMCPType(LTI_TYPE_MCP23008); // must be called before begin()
lcd.begin(16,2);
lcd.setBacklight(HIGH); // only supports HIGH or LOW
}
void loop() {
lcd.print(“Hello World!”);
delay(500);
lcd.clear();
delay(500);
}

RGB LCD Shield or compatible MCP23017-based module

#include <Wire.h>
#include <LiquidTWI2.h>
LiquidTWI2 lcd(0);

void setup() {
lcd.setMCPType(LTI_TYPE_MCP23017); // must be called before begin()
lcd.begin(16,2);
lcd.setBacklight(WHITE); // see LiquidTWI2.h for color options
}
void loop() {
lcd.print(“Hello World!”);
delay(500);
lcd.clear();
delay(500);
uint8_t btns = readButtons();
}

Note that you must call setMCPType() with the correct module type prior to the first call to begin().  The module type can be switched at any time during runtime by merely calling setMCPType() and begin() again. This allows you to create a single firmware which can run with either module, and store the module type in EEPROM.

When working in a memory-constrained environment, you can save memory by disabling the unneeded support.  Edit LiquidTWI2.h and comment out the #define for either MCP23008 or MCP23017.

For further speed gains, you can tweak the speed of the I2C bus.  See the included i2c_perftest example sketch.

Download: https://github.com/lincomatic/LiquidTWI2/downloads

Related Post: LiquidTWI2 v1.1.0 Released

AT90CAN Support for Arduino 1.0+

I have adapted the Arduino AT90CANxx support to work with Arduino 1.0+. Also, I have moved the code to github, so that it will be easier to update.  Note that the Arduino 1.0+ support is currently only alpha quality.  I have compiled a few sketches, but I also have found some which currently can’t compile.

You can always download the latest version at https://github.com/lincomatic/AT90CAN

It is easiest to download the whole repository as a zip file: https://github.com/lincomatic/AT90CAN/zipball/master

Follow the instructions in the README file.  For more information, see the post linked below.

Related Post: AVR CAN Bus Project – Step 1: Programming AT90CAN128 with Arduino

RedBearLab BLE Shield – First Look

SeeedStudio was kind enough to send me a BLE Shield. Designed by RedBearLab and sold by SeeedStudio,  the BLE Shield is a convenient way to experiment with Bluetooth Low Energy on an Arduino.  Bluetooth Low Energy is a feature of the Bluetooth 4.0 specification, which is aimed primarily at low-power, low-latency wireless applications.

Here is a top view of the BLE Shield:

The tiny square SMT chip in the upper left is the Nordic Semiconductor nRF8001, a single-chip BLE connectivity IC.

The pass through headers support the extra pins on the new Arduino Leonardo.  Currently, switch K1 should be left in the OFF position, as the OFF position is not supported.  The bottom of the board is not particularly interesting:

Note that it connects to the ICSP header, and that the pins are not extended through the top of the board, so if you want to stack it with a shield that also needs the ICSP pins, you will have to put the BLE shield on top.

Currently, BLE support on host devices is patchy at best.  On the Android platform, the Samsung Galaxy S3 contains a BT 4.0 hardware, but it’s currently not possible to program BLE, because the drivers are not yet available.

On Apple’s iOS platform, only the iPhone 4S/5, new iPad, and iPod 5th generation support BLE.  What’s nice is that there’s full support in the iOS SDK.  Unlike regular Bluetooth, for which very few profiles are available to the programmer in iOS (not even RFCOMM), you can easily design design your own custom BLE hardware and app.  What’s more, with BLE, you can avoid the expensive MFi hardware program, and simply submit your app for approval.

I am not sure what kind of SDK support is available in Windows, but I have ordered a cheap BT 4.0 dongle to try on my PC.

To program the Arduino, you must first download and install the BLE Shield Library.  To install the library, unzip the BLE and BluetoothLowEnergy folders into your <sketchbook>/libraries folder.  There is a sample BLEFirmata sketch in the BluetoothLowEnergy/examples folder.  It is compatible only with Arduino v1.0+.  The BLEFirmata sketch allows you to read/write the Arduino’s I/O pins from a remote device.  The current implementation of the library uses pins 8 and 9 for handshaking, so they are not available to your application.  Furthermore, communication with the board is via SPI (MISO/MOSI/SCK) pins.

If you have a compatible iOS device, after loading BLEFirmata into your Arduino, you can go to the App Store, and download RedBearLab’s free BLE Arduino app.  I installed BLE Arduino on my iPad under iOS6.  When you launch the app and tap the Connect button, it automatically finds and connects to your BLE Shield. Unlike regular Bluetooth, you don’t have to go to Settings->General->Bluetooth and pair the devices (I wonder what happens if you have multiple BLE devices in the area, and how security is handled).  Once the app finds your BLE Shield, it prompts you for the type of Arduino it’s attached to:

My Arduino Deumilanove is not listed as one of the options, but it works fine when you select Uno.  You can read or write any of the I/O’s in realtime.  If you select an analog pin, the app also gives you the option of treating it as analog or digital on input:

Here is the app displaying the value of pin A0 when configured for analog input, and the A0 pin is connected to the 3.3V pin:

Note that my USB cable is attached to the Arduino only to power it.

You can download the BLE iOS SDK and sample code from RedBearLab.  Their website also has lots of other documentation, as well as a forum for getting help.

I am looking forward to implementing some projects with the BLE Shield in the near future.