Working with NodeJS is fun and effective, but…
Note: this is rather a long post !!!
Coding in JavaScript is easy, and you have many modules that you can use.
For example, I have soon discovered that there is a module for MQTT. With this module you can easily publish MQTT messages to topics and subscribe.
You have also two good libraries, allowing you from a NodeJS program to interface with HW and to read from sensors: MRAA and UPM.
But to work in NodeJS on Intel Edison is NOT always easy and fun.
What is the main reason? Well I think it all points to the fact that the Linux distribution (well, it is not actually a distribution) is Yocto.
The NodeJS version shipped with Intel Edison, even if you download the latest available version (very. 3) is 0.10
This is an old version, with many important bugs.
For example, I have discovered soon that using MQTT if you send frequently messages from the board to the MQTT broker (let’s say every 10 sec.) very soon the programs stops working after 10 min.
Some test have showed me that the problem can be solved upgrading Node. It is ok with 0.12 version.
But the upgrade of the Node environment is not easy.
When I talk about environment I mean:
- NodeJS version
- The XDK agent (to be able to upload new Node programs directly from Intel XDK to the board, and launch them from the XDK)
- MRAA with Node bindings (add-ons)
- UPM with Node Bindings
Actually, now there is not a simple way, and it take a lot of manual work. And as I see, there is not a single, clear document describing how to do it.
In this blog post, I want to document the steps I have undertaken to upgrade NodeJS on Edison Board with an environment fully working.
High level steps:
- Flash the board with the latest Yocto version
- Configure Edison
- Upgrade MRAA and UPM libraries
- Upgrade the XDK agent
- Download and build the NodeJS (4.2)
- Set-up MRAA
- Set-up UPM
- Install MQTT
- Test all together
Flash the board with latest Yocto version.
The only way that always works for me is to use the flashall.sh script, from the command line.
Sometimes, I need to reboot my MAC, before to start the flashing procedure. This is needed to avoid that the flashing procedure timeout while waiting for the FTDI device to re-appear.
You download and unzip the distribution (Yocto Release 3.0), taken from here,
https://downloadmirror.intel.com/25871/eng/iot-devkit-prof-dev-image-edison-20160315.zip
then launch from the command line flashily.sh and connect through USB cables when requested.
It should take about 10 min
Configure Edison
At this point, you need to have the Intel XDK installed on your MAC or Laptop.
Launch the XDK and connect to the Edison using the serial connection (you have still the board connected with the two cables).
From the command line interface, launch
configure_edison —password
configure_edison —name
configure_edison —wifi
to setup a password, the hostname and to connect to the WI-FI network.
Upgrade MRAA and UPM libraries
From XDK, launch, upgrade libraries.
After, you can verify with opkg info
opkg info mraa
Package: mraa
Version: 1.0.0
Provides: mraa-dev, mraa-dbg, mraa-doc
Replaces: mraa-dev, mraa-dbg, mraa-doc, libmraa, libmraa-dev, libmraa-doc
Conflicts: mraa-dev, mraa-dbg, mraa-doc
Status: install user installed
Architecture: i586
Installed-Time: 1462025597
opkg info upm
Package: upm
Version: 0.6.2
Depends: mraa (>= 0.9.1)
Provides: upm-dev, upm-dbg, upm-doc
Replaces: upm-dev, upm-dbg, upm-doc
Conflicts: upm-dev, upm-dbg, upm-doc
Status: install user installed
Architecture: i586
Installed-Time: 1462025678
Upgrade the XDK agent
Again, from the XDK IDE (see preceding image).
Download and build the NodeJS (4.2)
First of all, remember that the space is limited. Therefore, you need to download the NodeJS distribution and start the build in a directory where you have enough space.
I have decided to create a downloads directory under /home/root
There, you can put the tree obtained from the tarball, downloaded from the NodeJS site.
But, I have hit one (of the many) annoying problem: if you simply download (with wget) the tar.gz file and explode it with tar xvf, when you launch configure on Edison you get a very strange error: the configure script (that is a Python script) complains that it cannot find the nodedownload module.
Well, I have found that the problem is in the tar utility, that doesn’t extract all the files (strange, but this is the reason). Actually, when I have unzipped the tar.gz file on my MAC I have found that the file nodedownload.py is there.
Solution: unpack the tarball file on your MAC, and upload all the resulting tree of directories and files on the Edison.
It will take some time, but I have no idea of a better solution.
then, update the XDK agent, from the XDK
The link where I took the tarball is:
http://nodejs.org/dist/v4.2.0/node-v4.2.0.tar.gz
Then, go inside the node-v4.2.0 directory and execute
./configure
make
It will take about three hours !
make install
Then, you have
root@thunder10:/# /usr/local/bin/node -v
v4.2.0
Update the XDK agent
Then, update the XDK agent, from the XDK IDE.
after, you should be able to upload a NodeJS application directly from XDK, connected to the board through WIFI, to the directory /node_app_list on the Edison board.
Setup mraa
Then, in the directory /node_app_list run
npm install mraa
After this, mraa is correctly linked to Node. In fact, the following blink code works
var mraa = require('mraa'); //require mraa
console.log('MRAA Version: ' + mraa.getVersion()); //write the mraa version to the Intel XDK consolevar myOnboardLed = new mraa.Gpio(13); //LED hooked up to digital pin 13
myOnboardLed.dir(mraa.DIR_OUT); //set the gpio direction to output
var ledState = true; //Boolean to hold the state of LedperiodicActivity(); //call the periodicActivity function
function periodicActivity()
{
myOnboardLed.write(ledState?1:0);
ledState = !ledState; //invert the ledState
setTimeout(periodicActivity,200);
}
Setup of UPM.
Under /home/root/downloads clone upm git repository
git clone https://github.com/intel-iot-devkit/upm.git
cd upm
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr
After, to compile only upm_grove (and produce the right jsupm_grove module)
cd src/grove
make
make install
To test, I have used the Grove Light sensor, attached to A1. This is the code I have used to test:
var groveSensor = require('jsupm_grove');
// Create the light sensor object using AIO pin 0
var light = new groveSensor.GroveLight(1);// Read the input and print both the raw value and a rough lux value,
// waiting one second between readings
function readLightSensorValue() {
console.log(light.name() + " raw value is " + light.raw_value() +
", which is roughly " + light.value() + " lux");
}
setInterval(readLightSensorValue, 1000);
and this is the output from the program:
Light Sensor raw value is 184, which is roughly 2 lux
Light Sensor raw value is 190, which is roughly 2 lux
Light Sensor raw value is 357, which is roughly 5 lux
Light Sensor raw value is 361, which is roughly 5 lux
It works fine under Node 4.2 !!!
Setup MQTT
Under /node_app_slot execute
npm install mqtt
and this is the code of the program that I have used to test that UPM and MQTT work under NodeJS 4.2
var mqtt = require('mqtt');
var groveSensor = require('jsupm_grove');
var MSG_TOPIC_NAME = 'sensors/SN3/msg';
var CONTROL_TOPIC_NAME = 'sensors/control/SN3';var SENSOR_ID = 'SN3';
var BROKER_URL = 'mqtt://broker_host';
var SLEEP_TIME = 3000; // 3 seconds
var PIN_TEMP = 0;// Create the temperature sensor object using AIO pin 0
var temp = new groveSensor.GroveTemp(PIN_TEMP);
// connect to the Broker
var mqtt_client = mqtt.connect(BROKER_URL, {'keepalive' : 60});//
// define events and callback
//
mqtt_client.on('close', handle_mqtt_close);
mqtt_client.on('connect', handle_mqtt_connect);
mqtt_client.on('reconnect', handle_mqtt_reconnect);
mqtt_client.on('error', handle_mqtt_err);
mqtt_client.on('message', handle_messsage);// the variable that will contain the object for the MQTT msg
// This is the format of the msg: {"id":"SN3","temp":"26"}
//
var msg = {};
var count = 0;function handle_mqtt_connect()
{
console.log("MQTT Connect...");mqtt_client.subscribe('CONTROL_TOPIC_NAME', handle_mqtt_subscribe);
}function handle_mqtt_subscribe(err, granted)
{
console.log("MQTT Subscribe...");
if (err)
{
console.log(err);
}
}function handle_mqtt_reconnect(err)
{
console.log("MQTT Reconnect...");if (err)
{
console.log(err);
}
mqtt_client.subscribe('CONTROL_TOPIC_NAME', handle_mqtt_subscribe);
}function handle_mqtt_err(err)
{
console.log("MQTT Error...");
if (err)
{
console.log(err);
}
}function handle_mqtt_close()
{
console.log("MQTT Close...");
}function after_publish()
{
// for now nothing...
}function handle_messsage(topic, message, packet)
{
console.log('Message received!');
console.log('msg = ' + message.toString());
}function readSensors()
{
count = count + 1;
console.log('***********************');
console.log("Iteration n. %d", count);
var rounded_temp = temp.value();
// build the object message
// that will be sent as a JSON message
msg.id = SENSOR_ID;
msg.temp = rounded_temp.toString();
// send with MQTT QOS = 1
if (rounded_temp)
mqtt_client.publish(MSG_TOPIC_NAME, JSON.stringify(msg), {'qos' : 1}, after_publish);setTimeout(readSensors, SLEEP_TIME);
}readSensors();
MQTT messages are sent to a Mosquitto broker installed on a Raspberry PI 2, connected to the WIFI network.
To verify that messages are correctly sent and received from the Broker, I have used the Eclipse Paho GUI Client:
No comments:
Post a Comment