There are some great Internet of Things hardware platforms, such as Raspberry Pi’s, ESP-32 based Arduino modules, Particle and Beaglebone to name just a few. Each of these systems have their strengths and weakness. Some are strong on the hardware side, like the Arduino modules, and others excel on the programming side like the Raspberry Pi.
The Yún is somewhat unique in that it’s a module with two processors, one that supports standard Arduino programming and a second processor that supports Linux and the OpenWrt wireless stack. The Yún ($59) has an Arduino Uno form factor and there are clones like the LinkIt Smart 7688 Duo ($18) in an Arduino Nano form factor.
In this blog I wanted to document some of key feature and functions that I worked through, namely:
- moving file – scp and ftp
- Python bridging to Arduino
- uhttpd Web Server – with Python CGI
- Yún REST API
- MQTT
- Yún mailbox
Yún Overview
The Yún, now in revision 2, seems to have been somewhat overlooked because of the all the low cost ESP-8266 and ESP32 based Arduino modules starting around $2.
Some the interesting features of the Yún include:
- Arduino code can launch and get feedback from Linux apps
- A bridge library allows Linux programs and Arduino to share data
- Arduino libraries for:
- Web client
- Web server
- Mailbox to Linux
- Yún has a lightweight web server, uhttpd, that can be used to Python, PHP, Lua CGI web programs
- Yún has a read/write REST API web service
Getting Started
The Arduino side of the Yún is available “out of the box” like any other Arduino module when you connect a USB cable into the module.
The Linux side however requires some configuration. Please see one of the guides on the Linux setup. Once your module is connected to your network, the Yun webserver can be used to configure features and add software components.
Another option for loading software is to use the opkg package manager from an SSH connection.
So for example to install nano, the simple text editor, enter:
opkg install nano
Moving File and Working in OpenWrt Linux
The OpenWrt Linux isn’t loaded with with an X-windows environment and this means that you can not run idle or leafpad etc. to do easy editing of program files. Nano is a good command line text editor but it’s not the same as a windows based editor.
To move files between a PC and OpenWrt you have some options. The two that I like are:
- scp – secure copy, this is built in both OpenWrt and Microsoft Window 10
- ftp – file transfer protocol. Needs to be installed in OpenWrt.
There are a few ftp servers that could be installed in OpenWrt, vsftp is a lightweight option and it can be installed by:
opkg update opkg install vsftpd
Once vsftpd is installed it needs to be enabled, this can be done from the command line or via the web interface.
Yún Bridge
The Yun Arduino bridge library allow variables to be passed between the Arduino code and a Python program. Below is an example that writes two random variables available, and it creates a “bridge1” variable that can be written from the Python side.
// Simple Yun Bridge Example // #include <Bridge.h> // create a bridge variable to get remote data char bridge_Value[10]; void setup() { Bridge.begin(); // this launches /usr/bin/run-bride on Linino } void loop() { // create 2 random bridge values, that are sourced from the Arduino Bridge.put("random1", String(random(1, 100))); Bridge.put("random2", String(random(1, 100))); // Called the bridge value "bridge1". This is the name used on the Python side Bridge.get("bridge1", bridge_Value, 6); delay(1000); }
An example to read/write in Python:
#!/usr/bin/python import sys sys.path.insert(0, '/usr/lib/python2.7/bridge/') from bridgeclient import BridgeClient as bridgeclient value = bridgeclient() message = value.get("random1") # get a value from Arduino print "Random1: ", message value.put("bridge1","1111") # set a value to Arduino
Yún uhttpd web server
The uhttp web server is used for Yun setup and configuration. This web server can also be used to for custom static pages and user web apps. To view/modify the web server settings:
nano /etc/config/uhttpd
Within this config file, you can enable custom web applications by defining an interpreter:
# List of extension->interpreter mappings.
# Files with an associated interpreter can
# be called outside of the CGI prefix and do
# not need to be executable.
# list interpreter ".php=/usr/bin/php-cgi"
# list interpreter ".cgi=/usr/bin/perl"
list interpreter ".py=/usr/bin/python
# Lua url prefix and handler script.
# Lua support is disabled if no prefix given.
# option lua_prefix /luci
# option lua_handler /usr/lib/lua/luci/sgi/uhttpd.lua
The default directory for user programs is: /www/cgi-bin
Python CGI – Get Values
To read the Arduino bridge values in a Python CGI program, add a file to the /www/cgi-bin directory. For my example I called the file p1.py :
#!/usr/bin/python
import sys
import cgi
sys.path.insert(0, '/usr/lib/python2.7/bridge/')
from bridgeclient import BridgeClient as bridgeclient
value = bridgeclient()
print "Content-type:text/html\r\n\r\n"
print '<html>'
print '<head>'
print '<title>Python CGI Bridge</title>'
print '</head>'
print '<body>'
print '<h2>Python CGI Bridge</h2>'
print 'Random Value1: ' + value.get("random1")
print 'Random Value2: ' + value.get("random2")
print '</body>'
print '</html>'
To run the python script on the web page you will need to change the file right to executable:
chmod +x p1.py
You can debug and see output from the command line.
root@yun1:/www/cgi-bin# ./p1.py
Content-type:text/html
<html>
<head>
<title>Python CGI Bridge</title>
</head>
<body>
<h2>Python CGI Bridge</h2>
Random Value1: 13
Random Value2: 24
</body>
</html>
If the output looks good, try the app from the Web page:
Python CGI – Put Values
There are a number of methods that can be used to send user input from a web page. A simple approach is to use a form. The form data can be read from the cgi.FieldStorage object, using a form.getvalue() call.
#!/usr/bin/python
# Import modules for CGI handling
import cgi
import sys
sys.path.insert(0, '/usr/lib/python2.7/bridge/')
from bridgeclient import BridgeClient as bridgeclient
value = bridgeclient()
# Create instance of FieldStorage
form = cgi.FieldStorage()
# Get data from fields
bridge1 = form.getvalue('bridge1')
if bridge1 != "" :
value.put("bridge1",bridge1)
print "Content-type:text/html\r\n\r\n"
print """
<html>
<head>
<title>Python CGI - Put Bridge Value</title>
</head>
<body>
<h2>Python CGI Form - Put Bridge Value</h2>
<form action = "/cgi-bin/p2.py" method = "post">
Enter BRIDGE1 value: <input type = "text" name = "bridge1"><br />
<input type = "submit" value = "Submit" />
</form>
</body>
</html>"""
The web page will call itself when the submit button is pressed.
Yún REST API
The Yún REST API is a web service that allow remote users and web browsers to view and set bridge values. I found the REST API to be a good tool for testing my Web CGI and Python applications
To view all bridge variables enter: http://yourYun_IP/data/get
To get a specific bridge value enter: http://yourYun_IP/data/get/my_bridge_value
To put a bridge value enter: http://yourYun_IP/data/put/my_bridge_value/value
IoT Connections – MQTT
For Internet of Things (IoT) projects you need to pass data from the Arduino and some server. The communications and the server would be something like MQTT or Redis.
The Yún does not have direct access to the Wifi or ethernet port so the standard Arduino libraries for MQTT or Redis etc. will not work. An alternative approach is load the protocol’s command line client on the Linux side and then Arduino can shell out to the Linux tool.
For example to load the Mosquitto MQTT command line tools:
opkg update opkg install mosquitto-client
To test MQTT publishing to a topic (mytag1) with a message of 249 on remote client (192.168.0.116) :
mosquitto_pub -h 192.168.0.116 -u username -P password -t mytag1 -m 249
To remotely subscribe to
mosquitto_sub -h 192.168.0.116 -u username -P password -t mytag1
An example of sending out four MQTT messages in Arduino:
/* Shell out to pass values to a MQTT command line pub */ #include <Process.h> void setup() { Bridge.begin(); // Initialize the Bridge Serial.begin(9600); // Initialize the Serial // Wait until a Serial Monitor is connected. while (!SerialUSB); } void loop() { Process p; String thecmd; String strval = String( random(0,100)); // create a string with host, username and password, -t is for the topic String theparams = "-h 192.168.0.116 -u pete -P pete -t "; int numtopics = 4; String topics[4] = {"tag1","tag2","tag3","tag4"}; for (int i=0; i < numtopics ; i++) { strval = String( (i*100) + random(1,99)); // create a random value - 0,100+,200+,300+ thecmd = "mosquitto_pub " + theparams + topics[i] + " -m " + strval; Serial.println(thecmd); p.runShellCommand(thecmd); // do nothing until the process finishes, so you get the whole output: while (p.running()); } // Wait 5 seconds and repeat delay(5000); // wait 5 seconds before you do it again }
It is also possible to create some bridge variables and pass them to a Python program that could do the MQTT communications.
Yún Mailbox
At present the mailbox only works in one direction, and this into the Arduino. Both the REST web interface and Python have writing functionality but no read capabilities (on the forums this has been identified, so a future revision may add this).
To write using REST:
http://yun_ip/mailbox/mymessagetext
To write using Python:
import sys sys.path.insert(0, '/usr/lib/python2.7/bridge') from bridgeclient import BridgeClient client = BridgeClient() client.mailbox("my_message")
The Arduino code to read message:
// Mailbox Read Example // #include <Mailbox.h> void setup() { // Initialize Bridge and Mailbox Bridge.begin(); Mailbox.begin(); // Initialize Serial SerialUSB.begin(9600); // Wait until a Serial Monitor is connected. while (!SerialUSB); SerialUSB.println("Mailbox Read Message\n"); } void loop() { String message; // if there is a message in the Mailbox if (Mailbox.messageAvailable()) { // read all the messages present in the queue while (Mailbox.messageAvailable()) { Mailbox.readMessage(message); SerialUSB.println(message); } SerialUSB.println("Waiting 10 seconds before checking the Mailbox again"); } // wait 30 seconds delay(10000); }
I’m not totally sure when I’d use a mailbox. The mailbox is a generic message and it’s not queued (only 1 message) so I think that using the standard bridging of values with get/put is more useful.
Final Comments
The Yun is missing a lot of networking libraries that are available with the ESP-8266 and ESP32 family of Arduino modules. In some cases like with MQTT that was a good Linux command line tool that could be used, but in cases like where you want to connect to a Redis server, you might have some challenges.
I really liked Yun’s built in uhttpd web server, this is far superior to the ESP-8266 Arduino web server library calls.
I found that putting logic into a combination of Python and Arduino could be a little confusing, but for projects with a lot of text or json data using Python would be a real plus. Also for projects where multitasking is required use the Linux process would be ideal.
Greaat blog you have here
LikeLike