Contribute to Open-Source with Crypto-Currency for Node-RED

Your first contribution to any open source software (OSS) community project is always intimidating. And yet, you probably feel that itch to contribute back to the software that you are using every day. Github has a default tag ‘Good first issue’ to help you get started, but even then, it can still be scary. Contributing your own flow or node to Node-RED is a great way to get started.

The first thing to do is to think of a good contribution. In my case, I was thinking of adding cryptocurrency related nodes. Then I searched the Node-RED library for existing nodes for ‘cryptocurrency’.

Here are the steps to get started:

  • Install Node-RED on Localhost
  • Create a Custom Node for CryptoCompare
  • Connect to CryptCompare API
  • Create a Node for ‘GET /CoinList’ Request
  • Create a Node for ‘GET /TopPairs’ Request
  • Add Nodes for ‘GET /HistoHour’ and ‘GET /SocialStats’ Requests
  • Add README.md and LICENSE.md
  • Update Package.json
  • Push Source Code to Github
  • Publish Package to npmjs.com
  • Add CryptoCompare to Node-RED Library
  • Testing the CryptoCompare Nodes
  • Contribute: Now It’s Your Turn

The Poloniex API node is one of the few currently existing nodes for ‘cryptocurrency’ it seems. Poloniex is a US-based digital asset exchange. ProgrammableWeb currently lists 98 cryptocurrency related APIs. So why not, for example, add a Node-RED node to support the CryptoCompare API.

Install Node-RED on Localhost

To install and run Node-RED on your localhost, you must have Node installed. With Node and npm installed, follow the installation instructions here, try to run Node-RED from the command line.

$ sudo npm install -g --unsafe-perm node-red
$ node-red
9 Jan 14:18:55 - [info]
Welcome to Node-RED
===================
9 Jan 14:18:55 - [info] Node-RED version: v0.17.5
9 Jan 14:18:55 - [info] Node.js version: v8.9.0
9 Jan 14:18:55 - [info] Darwin 16.7.0 x64 LE
9 Jan 14:18:55 - [info] Loading palette nodes
9 Jan 14:18:56 - [warn] ---------------------------
9 Jan 14:18:56 - [warn] [rpi-gpio] Info : Ignoring Raspberry Pi specific node
9 Jan 14:18:56 - [warn] ---------------------------
9 Jan 14:18:56 - [info] Settings file : /Users/Me/.node-red/settings.js
9 Jan 14:18:56 - [info] User directory : /Users/Me/.node-red
9 Jan 14:18:56 - [info] Flows file : /Users/Me/.node-red/flows_Remkos-MacBook-Pro.local.json
9 Jan 14:18:56 - [info] Creating new flow file
9 Jan 14:18:56 - [info] Server now running at http://127.0.0.1:1880/
9 Jan 14:18:56 - [info] Starting flows
9 Jan 14:18:56 - [info] Started flows

Open a browser and open the address where the server is running: http://127.0.0.1:1880/. 127.0.0.1 Is the default IP address for your local machine and Node-RED is running on port 1880.

Create a Custom Node for CryptoCompare

Now, I create an empty custom Node-RED node for the CryptoCompare API and name it ‘cryptocompare’. My cryptocompare’ node for Node-RED consists of at least the following three files:

  • package.json,
  • cryptocompare.js, and
  • cryptocompare.html.

This looks very familiar probably. The ‘package.json’ file is the configuration file for our node. A Node-RED node is essentially a Node.js package with a configuration file, a script file and a template file. In my example, I decided to call the node package ‘cryptocompare’. Node-RED requires a naming syntax for user contributed node packages that looks as follows: ‘node-red-contrib-cryptocompare’.

Wherever I have used ‘cryptocompare’ you need to replace ‘cryptocompare’ with the name of your own node. If you have a ‘Longer Name’ like this, then you rename the node to ‘longer-name’.

Now, create a new directory ‘node-red-contrib-cryptocompare’ and in the new directory, create three files ‘package.json’, ‘cryptocompare.js’, and ‘cryptocompare.html.’

simple package.json,

{
"name": "node-red-contrib-cryptocompare",
"node-red": {
"nodes": {
"cryptocompare": "cryptocompare.js"
}
}
}

cryptocompare.js

module.exports = function(RED) {
function CryptoCompareNode(config) {
RED.nodes.createNode(this,config);
var node = this;
node.on('input', function(msg) {
// on.input run your actual functionality here
// return 'send' the output for the next node
node.send(msg);
});
}
RED.nodes.registerType("cryptocompare", CryptoCompareNode);
}

cryptocompare.html

<script type="text/javascript">
RED.nodes.registerType('cryptocompare',{
category: 'blockchain',
color: '#65bf77',
defaults: {
name: {value:""}
},
inputs:1,
outputs:1,
icon: "cryptocompare_logo.png",
label: function() {
return this.name||"cryptocompare";
}
});
</script>
<script type="text/x-red" data-template-name="cryptocompare">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="cryptocompare">
<p>Node-RED package to support the CryptoCompare API.</p>
</script>

These files are pretty self-evident, I think. The only comment to make, is that in the template, you configure how the node appears in the Node-RED UI. Note that category defined as ‘blockchain’, which lets you group multiple nodes together under a header that I named ‘blockchain’, the color of the ‘cryptocompare’ node is the CryptoCompare green, and the icon is the CryptoCompare logo as a white icon.

You see the result below. Note the CryptoCompare icon. In my folder, I created a subfolder ‘icons’ with a ‘.png’ image of 20x30 pixels with a transparent background and white foreground. Those are the requirements to add custom icons to your node, which you can review on the Node-RED appearance doc.

The Information page is defined by the ‘data-help-name’ script.

If you double-click the cryptocompare node in the flow, the config page will open, defined by the ‘data-template-name’ script.

This is an empty shell for the CryptoCompare node in Node-RED. To test the node, I need to load it into my Node-RED UI, which I can do by symbolically linking my development directory to my Node-RED installation directory. In the custom node directory with my package.json file run ‘sudo npm link’, and in the Node-RED installation directory (typically ~/.node-red) run ‘npm link node-red-contrib-cryptocompare’. Restart node-red and you should see a header ‘blockchain’ in the nodes menu to the left with my ‘cryptocompare’ node.

Connect to CryptCompare API

Now we created the shell node or empty node, we can implement the CryptoCompare API functionality.

These are the available public API resources:

  • CoinList
  • Price
  • PriceHistorical
  • CoinSnapshot
  • CoinSnapshotFullById
  • SocialStats
  • HistoMinute
  • HistoHour
  • HistoDay
  • MiningContracts
  • MiningEquipment
  • TopPairs

Let’s start to create nodes for the CoinList, TopPairs, HistoHour and SocialStats APIs. Those nodes will give a user a lot of workflow potential already. Example requests:

$ curl -X GET https://www.cryptocompare.com/api/data/coinlist/
$ curl -X GET 'https://min-api.cryptocompare.com/data/top/pairs?fsym=ETH'
$ curl -X GET 'https://min-api.cryptocompare.com/data/histoday?fsym=BTC&tsym=USD&limit=60&aggregate=3'
$ curl -X GET 'https://www.cryptocompare.com/api/data/socialstats/?id=1182'

To implement multiple nodes we need to add an entry for each node to the ‘node-red.nodes’ property in the ‘package.json’ configuration file and map each node to its function file and matching template file.

Open and edit the ‘package.json’ file.

{
"name": "node-red-contrib-cryptocompare",
"node-red": {
"nodes": {
"coinlist": "coinlist.js",
"toppairs": "toppairs.js",
"histohour": "histohour.js",
"socialstats": "socialstats.js"
}
}
}

Create a Node for ‘GET /CoinList’ Request

Rename the ‘cryptocompare.js’ and ‘cryptocompare.html’ files to respectively ‘coinlist.js’ and ‘coinlist.html’. The CoinList API is super simple, it’s public, uses a GET method, and has no URL parameters.

coinlist.js

var request = require('request');
module.exports = function(RED) {
"use strict";
function CoinListNode(config) {
RED.nodes.createNode(this,config);
var node = this;
this.on('input', function(msg) {
var opts = {
method: "GET",
url: "https://www.cryptocompare.com/api/data/coinlist/",
timeout: node.reqTimeout,
headers: {},
encoding: null,
};
request(opts, function (error, response, body) {
node.status({});
if (error) {
node.error(error, msg);
msg.payload = error.toString() + " : " + url;
msg.statusCode = error.code;
node.send(msg);
node.status({
fill: "red",
shape: "ring",
text: error.code
});
} else {
try {
msg.payload = body.toString('utf8');
msg.payload = JSON.parse(msg.payload);
} catch(e) {
node.warn(RED._("httpin.errors.json-error"));
}
msg.headers = response.headers;
msg.statusCode = response.statusCode;

node.send(msg);
}
})
});
}
RED.nodes.registerType("coinlist", CoinListNode);
}

coinlist.html

<script type="text/javascript">
RED.nodes.registerType('coinlist',{
category: 'blockchain',
color: '#65bf77',
defaults: {
name: {value:""}
},
inputs:1,
outputs:1,
icon: "cryptocompare_logo.png",
label: function() {
return this.name||"coinlist";
}
});
</script>
<script type="text/x-red" data-template-name="coinlist">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="coinlist">
<p>Node-RED package to support the CryptoCompare CoinList API.</p>
<h3>CoinList</h3>
<p>Get general info for all the coins available on the website.</p>
<p>URL: <a href="https://www.cryptocompare.com/api/#-api-data-coinlist-" target="blank">https://www.cryptocompare.com/api/#-api-data-coinlist-</a>.</p>
<h3>URL Parameters</h3>
<p>None</p>
<h3>CryptoCompare</h3>
<p>getting cryptocurrency pricing, OHLC and volume data from multiple exchanges. We have integrated so far with: Cryptsy, BTCChina, Bitstamp, BTER, OKCoin, Coinbase, Poloniex, Cexio, BTCE, BitTrex, Kraken, Bitfinex, Yacuna, LocalBitcoins, Yunbi, itBit, HitBTC, btcXchange, BTC38, Coinfloor, Huobi, CCCAGG, LakeBTC, ANXBTC, Bit2C, Coinsetter, CCEX, Coinse, MonetaGo, Gatecoin, Gemini, CCEDK, Cryptopia, Exmo, Yobit, Korbit, BitBay, BTCMarkets, Coincheck, QuadrigaCX, BitSquare, Vaultoro, MercadoBitcoin, Bitso, Unocoin, BTCXIndia, Paymium, TheRockTrading, bitFlyer, Quoine, Luno, EtherDelta, bitFlyerFX, TuxExchange, CryptoX, Liqui, MtGox, BitMarket, LiveCoin, Coinone, Tidex, Bleutrade, EthexIndia, Bithumb, CHBTC, ViaBTC, Jubi, Zaif, Novaexchange, WavesDEX, Binance, Lykke, Remitano, Coinroom, Abucoins, BXinth, Gateio, HuobiPro, OKEX and the list keeps growing every month. We are your one stop shop for all your cryptocurrency APIs and data needs.</p>
</script>

Add the ‘request’ package as a dependency to the package.json file.

"dependencies": {
"request": "*"
}

Create a Node for ‘GET /TopPairs’ Request

The ‘GET /toppairs’ request has a few more requirements compared to the ‘GET coinlist’ request. It has four input parameters, two are required, so we need to add input processing and input validation for the ‘toppairs’ node and construct the URL with URL parameters. In the example below, I implemented this for the ‘fsym’ or ‘From Symbol’ input parameter per example, but you need to still add the required ‘tsym’, and the optional ‘limit’ and ‘sign’ URL parameters to complete the ‘toppairs’ node.

Create a new function file ‘toppairs.js’ and a new template file ‘toppairs.html’.

toppairs.js

var request = require('request');
module.exports = function(RED) {
"use strict";
function TopPairsNode(config) {
RED.nodes.createNode(this,config);
this.fsym = config.fsym;
var node = this;
this.on('input', function(msg) {
var urlParams = [];
// verify params
if(!msg.params || !msg.params.fsym){
if(!node.fsym || node.fsym===""){
var errMsg = "Error: required fsym parameter is missing";
node.status({
fill: 'red',
shape: 'ring',
text: errMsg
});
node.error(errMsg, msg);
return false;
}else{
urlParams.push("fsym="+ node.fsym);
}
}else{
urlParams.push("fsym="+msg.params.fsym);
}
urlParams = urlParams.join("&");
console.log("urlParams:"+urlParams);
var opts = {
method: "GET",
url: "https://min-api.cryptocompare.com/data/top/pairs?"+urlParams,
timeout: node.reqTimeout,
headers: {},
encoding: null,
};
request(opts, function (error, response, body) {
node.status({});
if(error) {
node.error(error, msg);
node.status({
fill: "red",
shape: "ring",
text: error.code
});
msg.payload = error.toString() + " : " + url;
msg.statusCode = error.code;
} else {
try {
msg.payload = body.toString('utf8');
msg.payload = JSON.parse(msg.payload);
} catch(e) {
node.warn(RED._("httpin.errors.json-error"));
}
msg.headers = response.headers;
msg.statusCode = response.statusCode;
}
node.send(msg);
})
});
}
RED.nodes.registerType("toppairs", TopPairsNode);
}

toppairs.html

<script type="text/javascript">
RED.nodes.registerType('toppairs',{
category: 'blockchain',
color: '#65bf77',
defaults: {
name: {value:""},
fsym: {value:""}
},
inputs:1,
outputs:1,
icon: "cryptocompare_logo.png",
label: function() {
return this.name||"toppairs";
}
});
</script>
<script type="text/x-red" data-template-name="toppairs">
<div class="form-row">
<label for="node-input-fsym"><i class="icon-tag"></i> fsym</label>
<input type="text" id="node-input-fsym" placeholder="fsym">
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="toppairs">
<p>Node-RED package to support the CryptoCompare TopPairs API.</p>
</script>

Add Nodes for ‘GET /HistoHour’ and ‘GET /SocialStats’ Requests

Having completed the ‘coinlist’ and the ‘toppairs’ nodes, to complete the CryptoCompare nodes, add the ‘histohour’ and ‘socialstats’ nodes next.

You can find the latest version of the ‘node-red-contrib-cryptocompare’ source code in my Github repo https://github.com/remkohdev/node-red-conrib-cryptocompare.

Add README.md and LICENSE.md

Before I publish my package to npmjs.com, I need to follow some requirements and best practices for documenting my package, like adding a proper ‘README.md’, ‘LICENSE.md’ and update my ‘package.json’.

You can check the repository https://github.com/remkohdev/node-red-contrib-cryptocompare and compare my README and LICENSE files.

Update Package.json

Version is a required property by npm, but other properties are recommended to make sure that your documentation is clear and easy to understand. The ‘package.json’ file below is likely far from complete, but it’s a decent start.

complete package.json

{
"name": "node-red-contrib-cryptocompare",
"version": "0.1.1",
"author": "Remko de Knikker <remkohdev@gmail.com>",
"keywords": [
"node-red",
"cryptocompare"
],
"description": "A collections of nodes to interact with the CryptoCompare API services.",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/remkohdev/node-red-contrib-cryptocompare"
},
"maintainers": [
{
"name": "Remko de Knikker",
"email": "remkohdev@gmail.com",
"web": "https://medium.com/@remkohdev"
}
],
"node-red": {
"nodes": {
"coinlist": "coinlist.js",
"toppairs": "toppairs.js",
"histohour": "histohour.js",
"socialstats": "socialstats.js"
}
},
"dependencies": {
"request": "*"
}
}

Push Source Code to Github

Create a new repository on Github named ‘node-red-conrib-cryptocompare’,

In the code directory on your localhost, initialize the Git repository

$ git init

Create and edit a new file ‘.gitignore’

node_modules
.DS_Store

Add all files, except the folders and files in ‘.gitignore’, to the git index, and commit all changes,

$ git add .
$ git commit -m 'init'

Link the local Git repository to the remote Master, and push all changes in origin to master,

$ git remote add origin https://github.com/remkohdev/node-red-conrib-cryptocompare.git
$ git push -u origin master

All your code should now be version controlled by Git and linked and updates to your remote repository on Github.

Test your code on localhost.

$ git clone https://github.com/remkohdev/node-red-contrib-cryptocompare.git
$ cd node-red-contrib-cryptocompare
$ npm install

To install the node modules on your localhost, install it into your Node-RED runtime.

$ sudo npm link
$ cd ~/.node-red
$ npm link node-red-contrib-cryptocompare

Run node-red.

$ node-red

Open a browser and go to the address http://127.0.0.1:1880. Test if you see the CryptoCompare category with the nodes we created, and create a test flow.

Publish Package to npmjs.com

This guide ‘Publishing npm Packages’ on npmjs.com explains the steps required to publish the ‘node-red-contrib-cryptocompare’ package to npmjs.com. Once we have published the package with the Node-RED prescribed naming to npmjs.com, the Node-RED Library will eventually be updated and list our package.

To publish to npmjs.com you must have an npm user account and log in first. Go to https://www.npmjs.com/~ and create an account, or if you already have an account log in.

You can also create an account via the command line with add ‘npm adduser’ command and ‘npm login’ command.

Once you’re logged in, publish your package to npmjs.com.

$ npm publish
+ node-red-contrib-cryptocompare@0.1.0

To update your package, you must increment the version number in ‘package.json’ before you publish the new version of the package again.

$ npm publish
+ node-red-contrib-cryptocompare@0.1.1

Add CryptoCompare to Node-RED Library

You have to wait probably half an hour before the Node-RED Library automatically updates with the latest publications from npmjs.com that are prefixed with ‘node-red-contrib-’. But then, voila, there it is. So you don’t have to do anything to add your package to the Node-RED Library,

Testing the CryptoCompare Nodes

Go to the Node-RED Library page for this simple example flow.

Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option.

Contribute: Now It’s Your Turn

If you want to contribute to this node package, go to https://github.com/remkohdev/node-red-conrib-cryptocompare. Create bugs, feature requests or questions in the Projects or Boards tab (if you use Zenhub). To contribute code, fork the repository and create a pull request for your new code submissions.

Like what you read? Give remko de knikker a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.