Introduction & Motivation :
The classic introduction to a new programming language is the ‘HelloWorld’ program and for a new microcontroller, it is the ‘Blink’ example. If you can get one of these going, you are on your way with whatever language or hardware platform you are learning. So there is nothing to be gained by yet another Blink example, unless maybe, you could blink 24 NeoPixels all at once, change their color and brightness and maybe you could house those 24 neopixels in a really cool 3D printed shade. Oh, and by the way, maybe there would be something to be gained if you could control all of this over Bluetooth Low Energy!
If you are interested, then keep calm and hack on!
This project is derived from 2 projects that piqued my interest and I decided to modify them to work with the Arduino/Genuino101.
The first project comes from Make: Bluetooth LE Projects with Arduino, Raspberry Pi, and Smartphones By: Don Coleman, Alasdair Allan, Sandeep Mistry ISBN-10:1457187094 (https://library.oreilly.com/book/0636920031932/make-bluetooth/toc). This is an excellent book for any maker interested in Bluetooth LE and Arduino. In my opinion, there is no better place to start. Chapter 7’s project is an Arduino/BLE controlled lamp using a NeoPixel ring. I changed the project to work with the Arduino/Genuino101. I had a chance to hear Don Coleman’s talk about BLE at the 2016 DC Maker Faire(http://makerfaire.com/maker/entry/57624/). He stated it would be easy to switch to the Arduino/Genuino101 because the BLE libraries were essentially the same. I was inspired to try and he was right!
The BLE Voronoi Feather Lamp (http://www.thingiverse.com/thing:1343925 or https://learn.adafruit.com/ble-feather-lamp/overview) is the second project. This is from the most excellent Ruiz Brothers by way of Adafruit. I enjoy 3D printing and wanted to finally combine a really neat 3D build with an Arduino project. Having it come from Adafruit and the Ruiz Brothers also increased my confidence that all would function as advertised and that the 3D build would be smooth and worth my time to print. Their project is designed to house the Adafruit Feather 32u4 Bluefruit LE (https://www.adafruit.com/products/2829) and not the Arduino. One of my objectives for future work is to make a complete enclosure compatible with the Arduino/Genuino101.
What you will need:
- Arduino/Genuino 101 board
- NeoPixel Ring - 24 x 5050 RGBW LEDs w/ Integrated Drivers PRODUCT ID: 2863 (https://www.adafruit.com/products/2863).
- USB Cable
- Wires, soldering iron, solder and wire cutters.
- Helping third hand( not required, but very helpful!)
- Arduino IDE 1.6.9 (https://www.arduino.cc/en/Main/Software)
- Evothings Studio 2.1.0 & Evothings Viewer (https://evothings.com/download/)
- A mobile device, such as a tablet or cellphone, to run Evothings Viewer on.
- Our modified app files, index.html, arduinoble.js and evothings-app.css
I will assume that you have a 3D printer or have access to one. If not, the electronics and software can all be tested without printing the Voronoi Feather Lamp, but it is really a super build and very satisfying when done.
Software:
The code for this project is commented and I encourage you to read it. Instead of providing a line-by-line breakdown of the how all the code works, I will highlight the areas that I think are most important, informative and interesting. With a BLE connected Arduino/Genuino 101 project, it is important to understand the overall layout of the software required. In addition to the sketch residing on the board , you will also have to write the software to run on the mobile device. The sketch will be written with the Arduino IDE and for the mobile app(called a hybrid wep app), we will use HTML/CSS/JavaScript with Evothings Studio.
Evothings Studio is designed to help you rapidly design and prototype hybrid web apps for the internet of things. You can learn more about this approach by taking advantage of the many tutorials on the Evothings website (https://evothings.com/doc/tutorials/tutorials.html). It is free to use. There are also Hackster.io projects using Evothings and the Arduino/Genuino101, (https://www.hackster.io/arduino/products/arduino-101-genuino-101).
The Arduino Sketch:
In order to model our lamp, let’s first consider what our connected thing is and then how this will be represented in our program and in terms of BLE services and characteristics.
Our physical thing is a NeoPixel lamp. Like any lamp we will want to be able to turn it on and off. The use of NeoPixels will allow us to control the color and brightness of our lamp. It is important when designing our code to keep in mind that while our characteristics are analogous to state variables or attributes in a program, they are not the state variables or attributes of the objects or data structures of our program. So if we wish to control a device, we will still have to represent it in the underlying programming language of the arduino, which is essentially C.
Let’s translate this model into Arduino C with a struct. The struct is a data type in C that allows us to combine different data types in one organizing unit. This is not absolutely required for this project, but it is a good time to learn and will be helpful to organize and keep track of the lamp “object” for this sketch.
We define our lamp struct as such:
struct LampStateStructure
{
boolean lampOn;
int brightness;
int green;
int red;
int blue;
};
struct LampStateStructure lampState;
We can access and set these variables using the following syntax:
lampState.lampOn = false;
Let’s translate the lamp model into BLE terms. The lamp is a service. This service should have an on/off switch, a brightness control and a color chooser. These three elements will be characteristics of our lamp service.
When we define the characteristics of our service, we will have to think of how we will represent the data of values of these characteristics and how they will behave. Specifically in this example, we will have a switch characteristic. A light switch is either on or off, so it might make sense to think of this as a boolean. There is no BLE boolean. However the basic unit of BLE data is the byte or unsigned char. This can work to our advantage, because although we may only initially need to represent on or off, we could potentially represent 255 more options under this characteristic. For example, maybe we could use another value of this characteristic to initiate special light effects or perhaps we could use the values to specify individual NeoPixels on the ring! For the brightness characteristic bytes are ideal and we can use the entire range of a byte value to represent our brightness choice.
The color characteristic is even more interesting. We can specify the color of our NeoPixel ring by specifying a Green, Red and Blue color value. The range of these values is 0..255. Again here the byte or unsigned char data type is ideal here. We could represent these each of the colors with 3 different characteristics, or one characteristic representing the array of values. One is a lonely number, but much more efficient. So will we go with one characteristic containing the three color-byte values.
Finally services and characteristics will each need universally unique identifiers or uuid’s to avoid conflict with other BLE peripherals out there. For custom services and characteristics, a 128 bit uuid is used. These are created by you for your custom service with the aid of uuid generators such as that found onant as we will have to specify these for each of our characteristics with a parameter, such as BLERead, BLEWrite, etc.
Finally services and characteristics will each need universally unique identifiers or uuid’s to avoid conflict with other BLE peripherals out there. For custom services and characteristics, a 128 bit uuid is used. These are created by you for your custom service with the aid of uuid generators such as that found on https://www.uuidgenerator.net/
This is how the BLE all looks in the sketch:
/**
* Setup our BLE service and characteristics here
*/
BLEPeripheral blePeripheral; // BLE Peripheral Device (the board you're programming)
BLEService lampService("917649A0-D98E-11E5-9EEC-0002A5D5C51B"); // Custom UUID
BLEUnsignedCharCharacteristic switchCharacteristic("917649A1-D98E-11E5-9EEC-0002A5D5C51B", BLERead | BLEWrite);
BLEUnsignedCharCharacteristic brightnessCharacteristic("917649A2-D98E-11E5-9EEC-0002A5D5C51B", BLERead | BLEWrite);
BLECharacteristic colorCharacteristic("917649A3-D98E-11E5-9EEC-0002A5D5C51B", BLERead | BLEWrite,3);
BLEDescriptor lampDescriptor("2902", "lamp");
The above code only sets up the BLE service and characteristics. Now we will have to interact with them. In my prior projects, the BLE interactions in the loop() portion of the sketch. This reflects what most of the BLE examples at show, such as the heart rate monitor sketch:
(https://www.arduino.cc/en/Tutorial/Genuino101CurieBLEHeartRateMonitor).
However after reading Chapter 7 of Make: Bluetooth LE Projects with Arduino, Raspberry Pi, and Smartphones and talking to one of the authors at the 2016 DC Maker Faire, I decided to follow the sketch structure coded there which uses an event handler model.
In this model, the loop() only serves to continually watch for activity from the BLE peripheral. If BLE actions or events are detected, the program control flow is directed to the appropriate action or function through event handlers.This is a closer representation of the way BLE is supposed to work and it is reflected in the arduino with code. I have seen the light! :) There are additional benefits to this:
1)We are not reinventing the wheel. The activity polling mechanism has been created for us, why recreate it in our own loop() function?
2) The code is cleaner and easier to read. There is a one-to-one connection BLE event and sketch activity. Why isn’t my characteristic not updating? Go right to the function and diagnose the problem!
3) The code will also allow easier modification and scaling. Adding a new characteristic won’t require digging through an ever lengthing loop(), but simply writing a new function.
This structure will work very well when the characteristics are all written to from a central as in this project. What will the code look like when characteristics are changed from within the the thing? It does, and for more on this please read Chapter 6 of Make: Bluetooth LE Projects with Arduino, Raspberry Pi, and Smartphones.
Now on to more code. We have 3 characteristics we want to change, the lamp switch, lamp color and lamp brightness. We will create a function or callback that will be executed anytime there is a change to a characteristic. The purpose of each of these functions will be to change the state of the lamp as it is represented in the struct and to initiate the appropriate action based on this change. Let’s look at the color change, as it is the most interesting.
In the setup() portion of the sketch, we connect specific characteristics with a specific event handler:
colorCharacteristic.setEventHandler(BLEWritten, colorCharacteristicWritten);
The event handler is then specified outside of both the setup() and loop() portions of the sketch:
void colorCharacteristicWritten(BLECentral& central, BLECharacteristic& characteristc)
{
const unsigned char* colors = colorCharacteristic.value();
lampState.green = colors[0];
lampState.red = colors[1];
lampState.blue = colors[2];
for (int i=0;i<NUMPIXELS;i++) {
ring.setPixelColor( i, ring.Color(lampState.green,lampState.red,lampState.blue)); }
ring.show();
}
We passed the parameter 3 when defining the colorCharacteristic. This specifies that the colorCharacteristic will hold 3 bytes of information. So when our mobile app changes the colorCharacteristic, it will send 3 bytes holding a value representing the R, G and B colors chosen. Because we have chosen an event handler model, updates to this characteristic are handled automatically.
And that's all I really want to say about the sketch! After you have the Arduino sketch up and running, you can debug it with a tool such as nRF Master Control before moving on to writing the mobile app. I recommend this, especially if you are new to writing BLE code or Arduino code. If you try and debug the sketch and the mobile app at one time, it will be much harder to trace down your bugs. Better to have ½ half of the software in working order first.
The Hybrid Mobile App:
The other component of the software for an IOT application is the portion of the code that will reside on our mobile device. For this we will use the Evothings platform and the triumvirate of HTML/CSS/JavaScript. The reason we can access the native features of our phone, in this case BLE, without writing a native app, is by using the use of the cordova/phonegap libraries. We won’t work with these directly, but will use the API provided for us by the good people at Evothings, named appropriately enough, easyble.js.
The hardest part of starting a project, is knowing where to start, so let’s start with the code for the a great working example found both on Hackster.io and Evothings: Arduino/Genuino 101 LED On/Off BLE example (https://evothings.com/doc/examples/arduino101-led-onoff.html).
I would like to highlight 3 specific areas in the mobile app. First will be how to connect an HTML UI element to a JavaScript action, using the writeCharacteristic method of the easyble.js library and a brief discussion of the color wheel interface.
Connecting the HTML button with an action is straight-forward. In the index.html file we add the following line to the <body>:
<button class="green wide" onclick="app.lampSwitch()">LAMP</button>
This will create a green colored button labeled “LAMP”. We connect the JavaScript action by stating that the JavaScript function app.lampSwitch() will be called when the button is clicked by stating onclick=”app.lampSwitch()”. As you might have guessed, this will function as our on/off switch for the lamp.
We then define the function in the <script> area of the index.html file:
app.lampSwitch = function() { app.device && app.device.writeLampCharacteristic( newUint8Array([0]), '917649a1-d98e-11e5-9eec-0002a5d5c51b'); }
This line will send the value of 0 to the characteristic specified by the uuid '917649a1-d98e-11e5-9eec-0002a5d5c51b'. If we wanted to increase the readability of the code we could attach this to a literal or variable. Both the data and the characteristic are then passed to the app.device.writeLampCharacteristic() function in the arduinoble.js file. This function is a wrapper around the writeCharacteristic function from the easyble.js library. We only need one function to send data to our lamp in arduinoble.js because we specify the characteristic and data sent from the index.html. Very simple, very elegant!
The Color Picker is an exciting element of the HTML design and I was inspired to use this element from the Bluefruit UI from Adafruit. In HTML5, you can easily capture the color of an image at any point where the user touches the image! For this app, I choose a circular color picker. The HTML5 canvas function canvas.getImage(x,y,1,1).data allows us to capture the image color at the x,y coordinate of the user’s touch. For a more in depth description of this, see How to create a color picker with HTML5 Canvas By Sara Vieira. (http://www.webdesignerdepot.com/2013/03/how-to-create-a-color-picker-with-html5-canvas/). There are many color wheel or color picker images on the web, I found mine at: https://commons.wikimedia.org/wiki/File:Color_Wheel.PNG
<script>
var canvas = document.getElementById('picker').getContext('2d');
var img = new Image();
img.src = 'colorWheel4.png';
$(img).load(function(){ canvas.drawImage(img,100,5,295,295);});
$('#picker').click(function(event)
{
var x = event.pageX - this.offsetLeft;
var y = event.pageY - this.offsetTop;
var imgData = canvas.getImageData(x,y,1,1).data;
var R = imgData[0];
var G = imgData[1];
var B = imgData[2];
app.changeLampColor( new Uint8Array([G,R,B]));
});
</script>
In this way, you could display any image on your UI and allow the user to change the lamp color based on the RGB data on any point on the image your user selects. If you had an image file, say “lizard.png” from EmojiOne you would put this image file in the same directory as the index.html which in this case is EvothingsStudio/MyApps/lamp/app/ and then change the image file name in the following line of code:
img.src = 'colorWheel4.png';
To
img.src = 'lizard.png';
Now you can enjoy the colors of your favorite EmojiOne (http://emojione.com/) emoji on your lamp by clicking on the image!
Yes it's a gecko, they didn't have a chameleon.
When I first wrote the HTML for this app, the slider did not look very appealing. So I did some googling and reading and found this site(url here).
For the app, locate the CSS file called evothings-app.css. It's located in the -- directory. When you scroll down to the INPUT FIELDS section, you will see that there is no style specified for the range slider. With the assistance of the range slider formatting tool above we can customize our range slider and then cut and paste the CSS directly into this file:
input[type=range]:focus {
outline: none;
}
input[type=range]{
-webkit-appearance: none;
width: 100%;
height: 25px;
cursor: pointer;
animate: 0.5s;
box-shadow: 1px
background: #AAB7B8;
border-radius: 19px;
border: 2px
}
input[type=range]::-webkit-slider-thumb {
-webkit-apperance: none;
box-shadow: 0px
border: 2px
height: 25px;
width: 36px;
border-radius: 15px;
background: #529DE1;
cursor: pointer;
-webkit-appearance: none;
margin-top: 0px;
}
That's all it takes to make a much more appealing and stylish slider to control brightness than default.
One other CSS item is worth mentioning. When I initially rendered the color wheel image on the canvas, it had a slightly grey background. I didn't like this and thought it would look better with a transparent background, this is accomplished by scrolling down to the VARIOUS ELEMENTS section and commenting out the background color item:
canvas {
padding: 7px;
border-radius: 4px;
border: none;
/* background-color: #f3f3f3; Default color: "Arctic" */
}
As you can see from the two examples above, one of the joys of taking the hybrid web app approach is the ease of creating UI and the rich set of tools provided with HTML and CSS to customize your app's UI. For myself, I only just begun the scratch the surface of HTML/CSS/JavaScript programming and can't wait to explore it more
Project Recipe:
This is an intermediate project. I am assuming you have the Arduino ide installed and setup for the Arduino/Genuino101. I am also assuming that you have EvothngsStudio up and running along with the EvothingsViewer app on the mobile device of your choice.
The project can be broken into 3 main elements: 3D printing, hardware, software.
3D Printing:
- For printing the enclosure and lamp shade, I downloaded the files on Thingiverse (http://www.thingiverse.com/thing:1343925 ) and following the instructions there. I don’t have much to add to this. The project base does will not fit an Arduino/Genuino101, this is a project for the future, maybe for you to do and share!
- I printed the shade with Taulman Bridge Nylon initially because it was the only translucent filament I had! It printed very well.
Hardware:
- Solder leads to the power(PWR), ground(GND) and input(Data Input) lines of the NeoPixel 24 Ring.
- Pull these leads through one of the openings on the enclosure base and seat the NeoPixel Ring in the groove.
- Connect the Data Input wire to Pin 6 on the Arduino/Genuino101.
- Connect the GND wire to the Arduino/Genuion101 ground pin.
- Connect the PWR wire to the 5 v pin on the Arduino/Genuio101. I have powered the lamp for several days in a row with the Arduino/Genuino101 plugged into my desktop with a USB cable without any trouble.
Software:
- Using the Arduino IDE, upload the sketch voronoiLamp.ino from the code section below to your completed circuit and enclosure.
- Start up Evothings Studio.
- Click on the Examples tab and scroll down to the Arduino101 LED On/Off BLE example and click the COPY button and give the folder a name for your project.
- You can then name the new app. I named mine lamp, Then press the CREATE button.
- Using you file viewer, find the directory of this project. On my desktop this was EvothingsStudio/MyApps/lamp/app.
- Enter the app folder and rename index.html to index_old.html(You may wish to look at the original in the future), replace it with the index.html file from this project in the code section below.
- The image you choose for a color picker will have to go in the same directory as the index.html file. You will also have to name this file colorWheel4.png in order for it to work with the index.html file as it is currently written.
- Now from the ../apps directory, follow the directory tree down to the /libs/evothings/arduinoble directory. Rename the arduinoble.js to arduinoble_old.js and replace it with the arduinoble.js file from this project in the code section below.
- Now go back to the ../app folder and follow the directory tree down to the /ui/css/ directory and rename evothings-app.css file to evothings-app_old.css. Replace it with the evothings-app.css file from this project in the code section below.
Starting it Up
- The Arduino/Genuino should be cnnected to your computer with a usb cable. The serial port monitor should be on.
- You should see a message like the following on the serial port monitor:
Arduino101/IntelCurie/NeoPixel-Voroni-Lamp/Evothings Example Started
Serial rate set to 9600
Bluetooth device active, waiting for connections...
- Now start up EvothingsStudio on your computer and EvothingsVIewer app on your mobile device
- Go to the Connect tab on EvothingsStudio and get your connect key.
- Enter this into the text box at top of the EvothingsViewer app and press the CONNECT button
- Go back to EvothingsStudio and click on the MyApps tab, find your project and click on the green RUN button.
- Once you see the page rendered, your are ready to Light Your Lamp
Conclusion:
My hope was to show how easy it is to create a Bluetooth LE connected app with Arduino/Genuino101 and EvothingsStudio and I look forward to hearing your comments, builds and variations on the theme!
"...If it had all just worked, it would have been far less fun! I mean it!"
- Cliff Lasser, from Reader Input in Make Vol 51 June/July 2016
Comments