Coin/Symbol | Network | Adress |
---|---|---|
Bitcoin (BTC) | BTC | 1LU7DtLiKkWe3aAXbhRhNAMUFdrapWuAHW |
Tether (USDT) | TRC20 | TK7f7TXozWVbkHxdArAJd2rELu725q1Ac5 |
Tether (USDT) | TON | UQDI4e7xm_B7O_REaYd5CoyEz1Ki08t0EPlUim022_K9B2xa |
Provides easy way to organize two - way communication between Arduino and Node.js, uses the serial port as transport layer. There are plenty of libraries that provides similar functionality, so what is the reason to create another one? Firstly I've tried the library called Johnny-Five, well this library itself is quiet cool, but if you need to drive your Arduino using Node.js, it's very unlikely that you'd prefer to call low-level Arduino subroutines (such as pinMode, digitalWrite and so on), unless you are building something really weird, or you don't know C++ at all, so the only way for you is to use JavaScript to program Arduino. Second library that I've tried to use in order to accomplish my project, called CmdMessenger, this one looks more like what I actually need, but I couldn't use it because it has no Node.js integration + API looks quiet complicated to me (not in terms of understanding but in terms of usage). So I've come up with the idea to create my own library, with blackjack and hookers. So here is the list of features that in my opinion had to be done in order to make this library uber cool:
- Smallest possible footprint, so library itself should not be bigger than your project, unfortunately this is not the case for both of the libraries listed above.
- All basic data types must be supported (null, boolean, floats, ints and strings). Note that arrays and objects, despite that they are widely used in JavaScript are not supported, because supporting it would either increase size of your scetch and decrease performance. Anyways if you really need arrays and objects, then you should consider using something like aJSON.
- Simple API, make things as intuitive and simple to use as possible.
- Two - way communication, means that Node.js can call previously registered Arduino subroutine and receive result of it's execution and all the way around, Arduino can call previously registered subroutine on Node.js side, so more JavaScript, Node.js, web 2.0, HTML5 than hardcore C++.
// include library
#include "RPCTransport.h"
#define LED_PIN 8
// instantiate RPCTransport and attach it to desired Serial
RPCTransport transport(&Serial);
// used to set LED state
void setState(RPCRequest* packet) {
// get desired state
bool state = packet->getBool(0);
// write LED state
digitalWrite(LED_PIN, state);
// clear request arguments
packet->clear();
}
// used to get LED state
void getState(RPCRequest* packet) {
// clear request arguments
packet->clear();
// read LED state
bool state = digitalRead(LED_PIN);
// add return value
packet->pushBool(state);
}
// this will be called when Node.js client is connected to the board
void registerMethods() {
transport.on("setState", setState);
transport.on("getState", getState);
}
void setup() {
// set the digital pin as output
pinMode(LED_PIN, OUTPUT);
// initialize Serial
Serial.begin(115200);
// initialize RPCTransport
transport.begin(registerMethods);
}
// called if there is serial data in the buffer
void serialEvent() {
// process incoming request
transport.process();
}
You start by instantiating RPCTransport and attaching it to desired serial port:
// instantiate RPCTransport and attach it to desired Serial
RPCTransport transport(&Serial);
When you ready to receive (or send) commands you call transport.begin and pass optional argument - callback function where you can register functions that will be available for calling from Node.js side (but don't forget to initialize serial communication first). Register public methods by calling transport.on, note that this method can only be called inside of the callback that is passed into transport.begin, attempt to call it in any other place won't take any effect. First argument is the name of your method (will be used to call it from Node.js), second argument is callback function, that will be executed when it's called:
void canBeCalledFromNode1(RPCRequest* packet) {
...
}
void canBeCalledFromNode2(RPCRequest* packet) {
...
}
// this will be called when Node.js client is connected to the board
void registerMethods() {
transport.on("command1", canBeCalledFromNode1);
transport.on("command2", canBeCalledFromNode2);
}
void setup() {
// don't forget to initialize Serial
Serial.begin(115200);
// initialize RPCTransport
transport.begin(registerMethods);
}
In order to process incoming messages, you have to call transport.process, if you don't do that, Node.js won't be able to call Arduino methods. There are two common places where you would call it, inside of loop subroutine or inside of special serialEvent subroutine (preferred):
void serialEvent() {
// process incoming messages
transport.process();
}
If you do everything right, Node.js can now execute methods on Arduino side, reading passed arguments is quite straightforward:
void canBeCalledFromNode1(RPCRequest* packet) {
// reading first argument as boolean
bool a1 = packet->getBool(0);
// reading second argument as float
float a2 = packet->getFloat(1);
// reading third argument as long
long a3 = packet->getInt(2);
// reading fourth argument as string
char* a4 = packet->getString(3);
}
Retrieving result is a bit tricky, same pointer is used to read arguments and to forward result to the caller. Before writing result, don't forget to clear the packet, otherwise everthing that you've received as an argument will be passed into result (echo mode):
void canBeCalledFromNode1(RPCRequest* packet) {
// read first argument as boolean
bool value = packet->getBool(0);
// if you don't do it, result will contain original request
packet->clear();
// push boolean into result set
packet->pushBool(true);
// push string into result set
packet->pushString("result from Arduino");
}
More realistic example, let's create method that will allow Node.js to call digitalWrite on Arduino side:
// include library
#include "RPCTransport.h"
// instantiate RPCTransport and attach it to desired Serial
RPCTransport transport(&Serial);
// our digitalWrite implementation available to Node.js
void myDigitalWrite(RPCRequest* packet) {
// read pin number
byte pinNumber = packet->getInt(0);
// read pin state
bool pinState = packet->getBool(1);
// do digitalWrite thing
digitalWrite(pinNumber, pinState);
// clear request arguments
packet->clear();
// let's respond with actual pinState
packet->pushBool(digitalRead(pinNumber));
}
// this will be called when Node.js client is connected to the board
void registerMethods() {
transport.on("digitalWrite", myDigitalWrite);
}
void setup() {
// initialize Serial
Serial.begin(115200);
// initialize RPCTransport
transport.begin(registerMethods);
}
// called if there is serial data in the buffer
void serialEvent() {
// process incoming request
transport.process();
}