Arduino Yún: Connecting a JeeNode to the Internet

Last week Paul handed me one of our new Arduino Yún boards and asked me to get a project going. I know the Uno and the Arduino environment well, but the Yún has an Atheros processor running Linux. I had little idea how I was going to wrap my head around the command-line oriented Linux part of the equation. I figured I’d give it a shot and see if I could have my way with the Yún’s Linux processor. As you’ll see, I had a lot more success than I thought I would.

Setting up the Yún’s wi-fi for the first time is fairly straightforward, so I’m not going to bother explaining how to do that when you can find a great start-up guide at the Ardiuno website. The only thing I’d add is that accessing the setting in my browser was hit or miss when I tried accessing http://[board name].local. Instead, I recommend memorizing the Yún’s IP address from the configuration window because accessing it that way (http://[IP address]) worked every time and the IP address is how you access the Linux processor through SSH. I should also mention that only the absolute latest version of the Arduino IDE, version 1.5.6-r2, actually supports the Yún, so make sure you install that too (you can find it here).

For my first Yún project, I wanted to focus on the Atheros processor because the Atmel processor is identical to that of the Arduino Leonardo and functions essentially the same. But what to do? As it turns out, we have a hot box that we use to keep the radios dry for our JeeLabs products, and when it was first set up we added a humidity sensor connected to a JeeNode USB that output humidity and temperature data to a LCD screen via an LCD plug (for the sake of product placement, I might as well mention that a Jee ProtoBoard was involved as well). The thing is, every now and then the darn thing would freeze and need to be reset, and with everything that goes on here no one really has time to check on the hot box with any kind of regularity. Clearly we needed a way to be able to check the status of the hot box from anywhere. That’s where the Arduino Yún would come in.

To start, let’s see how the data gets from the box to the Yún. Here’s the code for the JeeNode USB on the hot box itself. It’s pretty straightforward; the data points are collected, sent to the LCD for display, and cast to integers after multiplying by 100 to preserve two decimal places before being broadcast by the radio. There’s a one-second delay and then the whole thing repeats. Note the group number 68 from rf12_initialize; we’ll need to make sure the JeeLink on the other end gets configured with the same number.

#include <PortsLCD.h>
#include <Wire.h>
#include <LibHumidity.h>
#include <jeelib.h>

PortI2C myI2C (1);
LiquidCrystalI2C lcd (myI2C);
LibHumidity humidity = LibHumidity(0);

#define screen_width 16
#define screen_height 2
int Fan = 7;

void setup() {
  Serial.begin(9600);
  
  pinMode(Fan, OUTPUT);
  digitalWrite(Fan, LOW); //LOW is on

  lcd.begin(screen_width, screen_height);

  lcd.print("HUMIDITY STORAGE");
  delay(2000);
  lcd.clear();
  rf12_initialize(20, RF12_915MHZ, 68);
}

void loop() {

  int data[3];
   
  lcd.setCursor(0,0);
  lcd.print("HUMIDIY: ");
  float h = humidity.GetHumidity();
  lcd.print(h);
  data[0] = (int)(h*100);
  
  lcd.setCursor(0,1);
  lcd.print("TmpC");
  float t = humidity.GetTemperatureC();
  lcd.print(t);
  data[1] = (int)(t*100);
  
  lcd.setCursor(9,1);
  lcd.print(" F");
  t = humidity.GetTemperatureF();
  lcd.print(t);
  data[2] = (int)(t*100);
  
  while (!rf12_canSend())
    rf12_recvDone();
  
  rf12_sendStart(0, data, 6);
  
  delay(1000);
}

The code for the JeeLink that receives the data is even simpler. It just receives, unpacks, and prints the data sent by the JeeNode USB. You should also note the group number, 68, which matches the code on the transmitting JeeNode USB, and the serial baud rate, 57600, which we’ll need later.

#include <jeelib.h>

void setup() {
  Serial.begin(57600);
  rf12_initialize(18, RF12_915MHZ, 68);

  Serial.print("Receiving data...");
}

void loop() {
  if (rf12_recvDone() &amp;&amp; rf12_crc == 0) {
    int* buf = (int*) rf12_data;
    for (int i=0; i&lt;3; i++) {
      Serial.print(buf[i]);
      Serial.print(" ");
    }
    Serial.print("\n");
  }
}

Now that we’ve got the JeeLink streaming data over Serial, we can use the Yún to put it on the web. To do this, we’ll need to go directly to the Atheros processor, which we can do with a simple SSH in Terminal.

ssh root@[Yún IP address]

The first time you do this it will give you a security warning, so just enter “yes” to connect to the Yún. Once you’ve done that, we’ll need to install the FTDI drivers so the Yún can interpret serial data sent through the USB port. Luckily, the Yún’s Linux distribution Linino uses a package system that makes installing such things incredibly simple from the command line, so we’ll also install a second package we’ll need later.

opkg update
opkg install kmod-usb-serial-ftdi
opkg install pyserial

The first command just updates the package list so you only have to do this once. If you ever have trouble finding a package, try running update again.

With the FTDI drivers installed, the Yún can now interpret serial data sent to it from the JeeLink through the USB port. To put that data on the web, we need a Python script. That script, in all its in-line commented glory, is as follows:

#!/usr/bin/python
# This program reads off /dev/ttyUSB0 and writes an auto-updating html file with the results
# We have a jeelink on /dev/ttyUSB0 sending us data like "2580 7183 16132", which we divide by 100 to
# get humidity, temperature in celsius, and temperature in fahrenheit

import serial # Load pyserial
ser = serial.Serial('/dev/ttyUSB0', 57600, timeout=3) # Open the serial port at 57600

while True: # Loop forever
        data = ser.readline().split() # Split our data into an array, "2580 7183 16132" becomes [2580, 7183, 1613]
        if len(data) is 3: # The first line usually says something like "reading data..." ignore it.
                data = [float(thing)/100 for thing in data] # Divide each number by 100
                file = open('data.html', 'w') # Open the html file for writing
                file.write("<html><head></head>\n<body>\n \
<title>Yun server</title>\n<p>Humidity: {0:.2f}</p>\n<p>Temperature (C): {1:.2f} \
                </p>\n<p>Temperature (F): {2:.2f}</p>\n</body></html>".format(*data)) # Write the html page with the data-- *data unpacks it
                file.close() # Close the file

To make this available on the web, we have to move it to a special directory for files that we want the Yún’s server to host called “/www/”. We’ll also move our code (we named the file upload.py) to its own subfolder because it’s going to create a file.

#Starting from the Yún's root directory
cd /www/
mkdir humidity

In a new terminal window, navigate to the folder containing upload.py, then use the following command to copy it to our target directory.

scp upload.py root@[Yún IP address]:/www/humidity/upload.py

Enter the password, then go back to your original Terminal window.

cd ./humidity
chmod +x upload.py #make the python script executable
./upload.py #run it!

The last step is to build the webpage around the data to make it look nice. The index.html file, which will need to be moved to the same directory as upload.py, is as follows. I didn’t write this part (credit goes to Noah Beford), so I’m just going to call it a magical box. What I can tell you is that the stylesheet isn’t necessary, we just wanted it to look like the rest of our website.

<html>                        
<head>
<!-- FONTS -->
<meta charset="UTF-8" />
<link href='https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Roboto+Slab:400,700' rel='stylesheet' type='text/css'>
<!-- END FONTS -->
<link rel="stylesheet" type="text/css" href="humidity/style.css" media="screen" />
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript">
$(function(){
setInterval(reloadData,1000);
function reloadData(){
$("#data").load("humidity/data.html");
}
});
</script>
</head>
<body>
<b>Here's the data from the Modern Device dry box, where we keep the <a href="http://moderndevice.com/product/rfm12b-radio/">radio chips</a>:</b><br />
<br />
<div id="data"></div>

<p>This is being relayed from a <a href="http://moderndevice.com/product/jeenode-v6-kit/">Jeenode</a> mounted on the dry box to a <a href="http://moderndevice.com/product/jeelink-module-assembled/">Jeelink</a> plugged into an <a href="http://moderndevice.com/product/arduino-yun/">Arduino Yun.</a></p>

</body>
</html>

Now that everything’s in place, we can access the data stream by going to http://[Yún IP address].local/humidity. To make it available to the public, we set up a redirect for port 80 of our external IP address to the internal Yún IP address (more on that in a future post; for now, you can just ask a friend who’s a gamer). We also set up a special subdirectory on our website so you can see the final results by going to humidity.moderndevice.com.

Resources
GitHub repository for this project
Buy your own Arduino Yún

Stay tuned for more!

By Jeffrey Blum on April 2, 2014.