Connecting a Device Running on Embedded Linux to Exosite using Node.js


#1

Hi,

I am trying to connect a microcontroller (Beaglebone Black Rev C) to Exosite Portals so I can send data to the cloud (possibly a database) and display it to other users.

So far, my microntroller is able to connect to the internet (through a USB cable connected to a laptop and then some network configurations). I currently have downloaded the Node.js bindings for the Exosite One Platform API (JSON RPC over HTTP) to my microcontroller (currently located in root of the Beaglebone). I also created an account on Exosite Portals, selected a generic device, and received my CIK and data list alias.

My microcontroller is running Linux Debian, if that helps.

I want to be able to send data that I collect from my microcontroller ADC pins to the database. Given what I have so far, could you please help me on how to connect to the Exosite platform from my microcontroller using Node.js?

Thank you so much,

Thomas

Edit: I had already created a program to collect data from the ADC pins on the Beaglebone and store it in an existing text file.


#2

Some other details:

  • I am using Windows OS on my laptop.
  • I use puTTy to access the root of the Beaglebone Black

#3

I tried to run the test file in node-onep, but there was an error because the ./config module could not be found.

Is it possible that I may have to move the entire node-onep library somewhere else?


#4

HI @IndirectTV -

Thanks for posting here!

Your test didn’t work because your don’t have a config file for the test script to consume! You won’t have the ability to deploy our services to your machine locally, so if you want to use the test script, you will need to create your own template using the platform’s information.

Try printing out to the config-template file to see what the test is looking for:

$ cat config-template.js 

Once you have your bearings on what the test script is looking for, then you could copy the file contents and modify the file:

$ cp config-template.js config.js && nano config.js

Though the test-rpc.js script might not do what you want to do.

Also don’t forget to install the library’s dependancies before you continue, and that you have the node-onep in the node modules directory where you want to work:

{dir where you will run your code}$ npm install

As a quick start, I created a file called qs.js that uses node-onep to write to Exosite. A tree of my directory looks like this:

$ tree -L 3
.
├── node_modules
│   └── node-onep
│       ├── HISTORY.md
│       ├── README.md
│       ├── main.js
│       ├── node_modules
│       ├── package.json
│       ├── qs.js
│       ├── rpc.js
│       └── test
└── qs.js

####Writing data to Exosite

You will want to become familiar with our RPC API, in order to use node-rpc. Details on that procedure and all the others in that API can be found here: http://docs.exosite.com/rpc/#write. This is a must read to be successful using the library you have chosen.

Below I have copied the contents of my qs.js file so you can reference it to get started:

 var cik = "{CIK}"
 var alias = "string"
 var payload = "Hello world"
 
 
 // var rpc = require('rpc.js');
 var rpc = require('node-onep/rpc');
 rpc.call(cik, 'write', [{alias: alias}, payload],
   function(err, rpcresponse, httpresponse) {
   if (err) {
     console.log('error: ' + err);  
   } else {
     if (rpcresponse[0].status === 'ok') {
       console.log(JSON.stringify(rpcresponse[0].result));
     } else {
       console.log('Bad status: ' + rpcresponse[0].status);
     }
   }
 });

In the platform I have generic device with a string-type dataport with the alias string. After pasting my cik into this file, I can write "Hello world" to that dataport.

Later on, you will probably want to go through the Portals Getting Started Guide in order to get ready to create widgets, and start to visualizing your data.

Give this code a shot. You should be able to modify it to read your datafile, or put it in your ADC script. Let me know you can connect to Exosite with your Beaglebone.


#5

Hi @Martin again,

I am having some trouble trying to install the dependencies for node-onep. I had attempted to install the dependencies in root first and then move the node-onep into the node modules directory.

However, I kept getting error messages from the npm install:

I was only able to perform the npm install if I was in the node-onep directory. It currently works fine, but would there be any long-term problems if I had node_modules under node-onep?

Thanks again,

Thomas


#6

I think this is because Node doesn’t work like Python where modules and other dependancies are in some central directory and are referenced using a PATH. Additionally, you don’t have a package.json file that describes a program’s dependencies in your root’s home directory. This can be seen in one of the complaints:

npm ERR! package.json npm can't find a package.json file in your current directory. 

You will want to use npm to install your dependancies in the directory that holds your node code, and because you cloned our library for source, you will want to use npm to install the dependancies for our library.

That qs.js script should have node-onep as its only dependency, so if you move node-onep into a directory called node-modules that lives in your home directory and you already used npm to install non-onep’s dependencies, the qs.js code should work.


#7

@Martin

Okay. I removed and then reinstalled the npm in /usr/lib/nodejs, and then I was able to clone the node-onep into the node modules. Yay!

With the test file, I have been able to modify the config file, and now the test-rpc file is able to locate it. On the other hand, it is having some trouble with finding the onep-mock file.


#8

Nice! Glad to hear that.

Though, I don’t think that test-rpc.js does what you want it to do. Try getting the qs.js script to work.

-Martin


#9

I did get an output upon running the qs.js file. It did not display an error or display “bad status”, so I think it is working fine now. Yay (again)!

I’ll try reading my text file now and see if it works.

Thanks,

Thomas


#10

Yep! The script should return the timestamp at which the value was written. You can read back your dataport to see the value.

Don’t forget that Exosite supports 1 second timestamp resolution. This means that you can upload data into a dataport once a second. If you are going to read from a file and 'write the contents, don’t forget to include a sleep, or you will get bad request responses from the server.

-Martin


#11

Here is my code so far (minus the CIK and the data alias):

I just copied and pasted my code for collecting data into the quick start file instead.

I ran the file and looked onto my Exosite Portal, but I did not find anything there.

Could you please tell me if Exosite is able to accept arrays?

Thanks

Thomas


#12

Exosite dataports support floating point, integer, and string data. This means that sending an array ‘as is’ won’t work. If you wanted to send an array of data, you might want to consider using multiple dataports, or encode you data as a string.

For information on data formats check-out: https://support.exosite.com/hc/en-us/articles/203151380-Data-Format.


#13

Hi @Martin again,

I tried converting to an integer using Math.round(). However, I keep getting an “invalid” message when I try sending the data to Exosite.

The top image is the error output, while the bottom image is my code.


Could you please help?

Thanks,

Thomas


#14

Hi @inderectTV,

It seems like you are not leaving enough time between write calls. Remember from Martin’s earlier post that Exosite supports 1 second timestamp resolution. Your code appears to make a write call every 100 milliseconds (0.1 seconds), which is probably why you are sometimes getting this error message.

-Joey


#15

@joeylink and @Martin,

If I wanted to a series of data in one string in order to meet the 1 second timestamp resolution, how would Exosite parse that data? Would it be parsed automatically once on the Exosite database?


#16

It wouldn’t be parsed automatically, but you could easily setup something to parse for you. You could create a collection of your data, encode it in a string, perform a write, and have a script waiting in Exosite to decode your information.

This is a common use of the Exosite scripting engine .

Take a look at this example that parses a string-encoded JSON blob and then writes the matching key’s values to some dataports:


#17

Maybe parse wasn’t the right word for me to use. I was thinking that I would need more a delimiter instead.

I have a string that contains ten data points, separated by a space that has already been sent to Exosite.

I think I would want to have the space be a delimiter to separate the data. Then I could parse it and send it to database.

How would I modify the existing Lua script to use a delimiter?

Edit: The values have been rounded.


#18

If you want to use the method of using spaces as delimiters and creating an array (through lua), the gmatch function is probably the easiest to use. Here’s an example of how gmatch can be used in this manner

local random_string = "How do I take this string and split it into a table of strings?"
local string_array = {}
for i in random_string:gmatch("%S+") do table.insert(string_array, i) end

Once you have done this within your lua script, You can reference each data point by its index within the array (remember that in lua, indexes start at 1). From this you should be able to parse your data and send it to the database.

Another method would to be to send the data as a string-encoded JSON table, as mentioned above by Martin, then use the json.decode function within your lua script to convert it to a lua table. This may be easier to do since JSON is native in Node. Here’s the basic syntax for this conversion:

local lua_table = json.decode(<jsonBlob>)

Using this method you can access each datapoint by its key value. Here’s the basic syntax for doing this:

local <datapoint_name> = lua_table.<key_name>

This will take whatever value is associated with the key key_name and store it in datapoint_name.

-Joey Link


#19

@joeylink and @Martin,

Could you please tell me what is this error supposed to mean? I keep running into it whenever I update my script.
[string “local packet = alias[‘data_alias’] …”]:9: attempt to index local ‘meta’ (a nil value)

Note that in my script “data_alias” has been replaced with my own data alias. Also note that in the picture below my alias name has been removed (the white spaces).

Edit: I just deleted the lines containing meta.
Edit 2: I got a new error:
[string “local packet = alias[‘SGD 1’] …”]:15: bad argument #1 to ‘gmatch’ (string expected, got nil)

I thought that the lua already would have decoded the packetval into “data”, so then I would have gotten a string, right?


#20

Also, how do I ensure that my data is sent directly to the Lua script?

It seems as if the data is bypassing the script and showing up directly on the database (as a value of “1”).