Arduino 101 with an Intel Edison - Hooking up JSON to an LCD Screen
Hanselminutes and CodeNewbie are teaming up to produce two new podcast episodes a week for the month of March, featuring incredible makers in the hardware space. There will be new content every weekday in March, so bookmark http://www.marchisformakers.com and join us!
- CodeNewbie is the most supportive community of programmers and people learning to code. Tune in every week for stories about people on their coding journey.
- Subscribe via RSS or on iTunes. Published Mondays.
- Hanselminutes: Fresh Air for Developers is a weekly talk show that brings interesting people together to talk about the web, culture, education, technology and more.
- Subscribe via RSS or on iTunes. Published Thursdays.
Our hashtag for this event is #MarchIsForMakers and YOU, Dear Reader, can help us out by being our Street Team.
Share our website http://marchisformakers.com!
...with friends, kids, teachers, family, anyone you think my be benefit from learning about hardware and today's maker culture.
This is Week 2! At the end of March we'll have as many as 10 great podcasts, amazing guests, Live Google Hangouts, blog posts, Twitter Chats on Wednesdays, and a huge collection of links and projects for you to explore.
Please note that I'm learning. I'm sure some of you are fantastic experts, while others are working on Hello World. If you find errors, naïve or otherwise, in my code or solution, DO let me know in the comments and I'll update this post with notes and asides so we can all learn!
I wanted to learn a little about Arduino this week. It's an huge and enthusiastic community based around an open-source electronics platform. The hardware is small and relatively inexpensive, and it brings hardware hacking to folks (like myself) that may not feel up to doing really low level electronics work. There or stackable "shields" you can plug on top and easily add new features, screens, sensors, and more.
There's lots of different choices for Arduino development, including some more interesting versions like the Intel Edison with Arduino Breakout Board. The Intel Edison supports not just Arduino, but also can run a full version of Yocto Linux, and can run Python and node.js. I have an older Arduino Atmega328 which was like $12.99, but I wanted a more flexible option that included on board Wi-Fi. Getting Wi-Fi connectivity is kind of a hassle if it's not built in.
The Arduino Yún is a great choice, but I figured I'd spend more for the Edison and get a lot more options. I also got the "Seeed Studio Grove Starter Kit." This is a cool Arduino Shield that lets me (and the kids) attached sensors, buttons, screens, and lots of other stuff without soldering!
I download the Arduino software, but also found that Intel now has a complete Integrated IoT Windows 64 Installer that will get everything you need to get started with the Intel Edison. It makes it REALLY easy to start.
I tried a few small "Sketches" out, turning on a light with a button press, and such.
But I wanted to make something more interesting to me personally. I'm a Type 1 Diabetic, and I wear an insulin pump and Dexcom Continuous Glucose Meter. They are connected to the cloud via a project called Nightscout. Nightscout takes my sugar values and pushes them into Azure, where they are available via a JSON web service.
NOTE: I've put my Arduino Sketch on GitHub here. https://github.com/shanselman/NightscoutArduinoPlayground
Nightscout has a /pebble endpoint that is used to feed the Pebble Watch Face and show folks their blood sugar on their wrist. I thought it would be cool to hook up an Arduino to get my blood sugar from the cloud and display it on an LCD. It'll show the current value, change the background to green/yellow/red to display risk, and then a custom character to show trends (flat, up, down, etc).
The JSON the Nightscout service returns looks like this, but I just want the "sgv" value and the "direction."
{
status: [{
now: 1426017007130
}],
bgs: [{
sgv: "102",
bgdelta: 2,
trend: 4,
direction: "Flat",
datetime: 1426016912000,
filtered: 115232,
unfiltered: 118368,
noise: 1,
rssi: 191,
battery: "59"
}]
}
I needed to bring in three libraries to achieve my goal. Remember I want to:
- Connect to my Wi-Fi network
- Download some JSON and parse it
- Display values on an LCD screen
So I needed:
- #include <WiFi.h> //The Intel Edison has Wi-Fi built in
- #include <aJSON.h> //JSON is hard to parse on small memory devices, so this aJSON library helps
- #include "rgb_lcd.h" //I'm using the Grove - LCD RGB Backlight
As with all problems when you're learning new things, you'll want to break them down one at a time.
I wanted to just display a string on the LCD, that was easy, there's lots of examples online in the Arduino community.
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Hello World");
Connecting to Wi-Fi was pretty easy also:
while (status != WL_CONNECTED) {
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 3 seconds for connection:
lcd.setCursor(0, 0);
lcd.print("Waiting...");
delay(3000);
}
When doing an HTTP call (given the libraries I was learning about) it's pretty low level. Constrained memory Arduinos (not like the Edison) don't seem to have SSL support, nor do they have high-level HTTP libraries. I had to craft the HTTP headers manually:
lcd.print("Connecting...");
if (client.connect(server, 80)) {
lcd.clear();
lcd.print("Server connected");
// Make a HTTP request:
client.println("GET /pebble HTTP/1.1");
client.println("Host: hanselsugars");
client.println("Connection: close");
client.println();
}
Then I spin through the HTTP Response looking for the start of the JSON, and store it away. At this point I'm wondering if I'm doing it wrong. It isn't very robust.
boolean jsonFound = false;
int bytes = 0;
while (client.available()) {
char c = client.read();
//look for first {, yes it could be in a cookie but I'm thinking positively.
if (c == '{') jsonFound = true;
if (!jsonFound) continue;
stringBuffer[bytes++] = c;
if (bytes >= MAXBUFFER) break; //that's all we have room for or we're done
}
Then once I've got the stringBuffer, I use the aJSON library to get the values I need. This isn't pretty, but it's how you use this library.
I also added a little bit to turn the color of the screen red/green/yellow.
if (root != NULL) {
aJsonObject* bgs = aJson.getObjectItem(root, "bgs");
if (bgs != NULL) {
aJsonObject* def = aJson.getArrayItem(bgs, 0);
if (def != NULL) {
aJsonObject* sgv = aJson.getObjectItem(def, "sgv");
String bg = sgv->valuestring;
int bgInt = bg.toInt();
if (bgInt > 180) lcd.setRGB(255, 0, 0);
if (bgInt > 150 && bgInt <= 180) lcd.setRGB(255, 255, 0);
if (bgInt <= 150) lcd.setRGB(0, 255, 0);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Glucose (mg/dl)");
lcd.setCursor(0, 1);
lcd.print(bg);
}
I also created some custom characters to show trends, based on a string (pretending to be an enum) that comes back from the JSON service. For example, an up arrow:
byte SingleUp[8] = {
B00000,
B00100,
B01110,
B10101,
B00100,
B00100,
B00100,
B00000
};
All the questionable code is up at https://github.com/shanselman/NightscoutArduinoPlayground
At this point I'm confused/learning about a few things:
- It runs for a while and then stops.
- I don't know what state it's in.
- I would like it to call out to the web service every 5 min and update the LCD. I suspect I am not managing Wi-Fi connection state correctly (as in, not at all).
- So the question is, how does one take a working prototype and turn it into a real appliance that can run forever?
- I'm reusing the stringBuffer which is a bad idea. I need to clear it out.
- Sometimes the Custom Characters are corrupted on the screen.
- No idea why. It works 8 out of 10 times. Perhaps it's an Edison bug or a SeeedStudio bug.
When I get it working reliably, I'd like to 3D Print a case and mount it somewhere. :)
Arduino for Visual Studio
One other thing I found out, there's a fantastic add-in for Visual Studio that will give you a great Arduino Development Environment inside of Visual Studio. It includes simple debugging, breakpoints, a nice serial monitor and more. I'm still finding debugging to be challenging as local watches and step over isn't supported, but it's vastly superior to the tiny Arduino IDE.
Arduino Emulator
Don't have an Arduino or a breadboard? Check out http://123d.circuits.io online. It's amazing. It's an Arduino Circuit Simulator online. Check this out!
You can setup boards, write code, and practice in software before you test it out on hardware.
Don't forget, visit http://marchisformakers.com, tell your friends and tweet us at #MarchIsForMakers!
Sponsor: Big thanks to Aspose for sponsoring the blog feed this week! Are you working with Files? Aspose.Total for .NET has all the APIs you need to create, manipulate and convert Microsoft Office documents and many other formats in your applications. Start a free trial today.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
If that's right, then you'd need to completely change "loop" to be a state machine. While the socket is connected, you'd want to read available data and then return. Only process the data when the socket is disconnected. Note that you should send the "Connection: close" header so that the server will actually close the socket.
Reliable HTTP connection management is quite a bit more complex. For a truly reliable client, you'd have to implement some form of no-response timeout at least to avoid the half-open problem.
Since you're using a Galileo and it has a full Linux environment available you might look into putting all the complex logic like talking to web services, parsing text, etc. into a process you run yourself in Linux. Something like a python, node.js, etc. script that talks to the web service and sends/receives data with the Arduino sketch would be a lot easier and save you the pain of writing all the code to do HTTP requests, etc. I'm not sure off-hand what ways you can use to communicate between the Arduino sketch and your own scripts, but check the Galileo forums to see if there are some examples.
And yep a Raspberry Pi could work to do something like query a web service and display data on a small LCD. Here's an example of how to use python on a Raspberry Pi to talk to an LCD.
Then crontab your python script to run every 5-10 mins.
Something similar to what the following guy did:
www.jeremyblum.com/2014/01/06/epaper-weather-station/
I was able to replicate this ePaper project on Yun and it works without any issues so far...
[...] I wear an insulin pump and Dexcom Continuous Glucose Meter. They are connected to my butt via a project called Nightscout.
Tom - They are all at either hanselminutes.com or at codenewbie.org/podcast
Tony - This is an Edison, is that very different from a Galileo? Yes, I totally get that I'm using an overpowered Intel as an Arduino (my other Arduino is being used on another project). I should probably have used a YUN, or as you rightfully say, used a higher level language. Thanks for your comment!
Alex - Yes it likely would! I should take a look and see if there are Python libraries for the LCD screen I'd like to use. I realize this could be a simple script, but I also wanted to see how it works on a Arduino using their lower level constructs.
Also you wouldn't need python library for LCD as it would still stay at the Arduino controller side and you just need to modify/minify your Arduino c-program to be able to get data from Python script somehow and display it... (Sorry if it's not a clear explanation, I am really bad at it)
love the #MarchIsForMakers initiative!
Definitely sparked my intereset in the maker game (again) and I unburied my Arduino kit yesterday.
Out of personal interest: did you run the Arduino IDE on one of your High DPI machines? I did so on my Yoga 2 Pro and the experience is very poor. Any ideas, advice on that?
The Nightscout data is not standard JSON per se as it doesn't have quotes around object's member names.
Unfortunately ArduinoJson doesn't support this yet, but soon it should.
You could get the sgv and direction values with 2 calls:
int sgv= jRead_int( jsonBuffer, "{'bgs' [0 {'sgv'");
char direction[32]; jRead_string( jsonBuffer, "{'bgs' [0 {'direction'", direction, 32 );
Yours,
TonyWilk
Thank you for this great review and the interesting pointers.
Similar to Visual Micro for Visual Studio on Windows, there's embedXcode for Xcode that runs on Mac OS X.
It supports both the Wiring / Arduino framework and native applications for Yocto on the Intel Edison board.
Learn more at http://embedxcode.weebly.com
Comments are closed.