Serial port communication between Nodejs and Arduino - node.js

I am trying to communication between Arduino and Nodejs. But problem is when I communicate between I got correct reading as well as some garbage reading in between correct reading. Still cant understand how to resolve this problem ?
Here is the Nodejs part which is used to read data from COM port
var SerialPort = require("serialport").SerialPort;
var serialport = new SerialPort("COM23",{baudrate:9600});
serialport.on('open', function(){
serialport.on('data', function(data){
console.log(data[0]);
});
});
Here is my simple Arduino code
int led = 13;
void setup() {
Serial.begin(9600);
pinMode(led, OUTPUT);
}
void loop() {
digitalWrite(led, HIGH);
Serial.write(1);
delay(1000);
digitalWrite(led, LOW);
Serial.write(0);
delay(1000);
}

Limit the size of the data transferred, also define a parser for the serial transmission.
take a look to the serial port documentation https://github.com/voodootikigod/node-serialport#parsers
You have two options "raw" and "readline".
Out of the box, node-serialport provides two parsers one that simply emits the raw buffer as a data event and the other which provides familiar "readline" style parsing. To use the readline parser, you must provide a delimiter as such '\n'
here is an example for node.js.
var sp = new SerialPort('/dev/tty.usbmodem14111', {
//sp.parsers.readline('\r')
//serialport.parsers.raw
baudrate: 9600,
parser: serialport.parsers.readline('\n')
});
in the Arduino side, use the Serial function println();
Serial.println("your message to the node server");
I hope this helps.

Related

Send BEEP command to barcode scanner connected by serial port using Node's SerialPort library

I have a programming problem with my Barcode scanner connected to PC by serial port (COM3).
I'm using Node.js with Electron and trying to reading data from the scanner and depending on the specific condition send command to device to beep.
Reading data from scanner is not the problem. The problem is sending command to make a scanner beep.
My code:
const { SerialPort } = require('serialport');
var sp = new SerialPort({
path: 'COM3',
baudRate: 115200,
});
sp.on('data', function (data) {
const number = data.toString('utf-8');
console.log('Data:', number)
if (number == 5901882110014) {
sendData();
}
})
function sendData() {}
I want send command to scanner to beep if, for example received barcode is 5901882110014.
How can I approach to this problem?
My scanner is Zebra DS2278:
Scanner Manual 1
Scanner Manual 2

Communicating with ESP32 via serial with serialports.js (node.js)

I have an esp32 board loaded with this software which is logging values about the number of detected Wi-Fi and Bluetooth devices detected via LoraWAN. In senddata.cpp it seems to be logging out the values that I need (though I'm not quite sure I understand how or where it is sending them via serial):
ESP_LOGD(TAG, "Sending count results: pax=%d / wifi=%d / ble=%d", count.pax, count.wifi_count, count.ble_count);
I set up a node.js app with the SerialPort.io library to be able to read data coming over serial. I've successfully identified the COM port on my PC that is receiving data, and I can log out the data buffer as follows:
const SerialPort = require("serialport").SerialPort;
const serialPort = new SerialPort({
path: "COM4",
baudRate: 9600,
autoOpen: false,
});
serialPort.open(function (error) {
if (error) {
console.log("failed to open: " + error);
} else {
console.log("serial port opened");
serialPort.on("data", function (data) {
// get buffered data and parse it to an utf-8 string
console.log(data);
data = data.toString("utf-8");
console.log(data);
});
serialPort.on("error", function (data) {
console.log("Error: " + data);
});
}
});
Which yields output in node.js as a buffer, e.g. <Buffer bc 08 AD>, but after the toString("utf-8") it is a bunch of gibberish. Clearly I am not encoding or decoding the serial output properly, but I'm not sure where to make adjustments. Does anyone know how I can get this serial output into the proper format to use in node.js?
--- Update Re: Questions ---
The board is a ttgo / lilygo lora32 - the library I used seems to say it supports both this board and communication over SPI. I am able to get readable data via the debug console with the platform.io extension for VSCode on Windows / Mac. I believe the baud is 9600, which was the only thing I seemed to need to specify on the serialports.io side.
I did receive this advice from the library author:
You need
a messagebuffer, to store the payload
a queue, as buffer for the serial data
a protocol, suitable for your application
1+2: see spislave.cpp (change the SPI transmit calls by serial port calls)
3: consider overhead and checksum, e.g. transfer the payload as byte array or UTF8 string, e.g. comma separated string with checksum, as used in NMEA.
Unfortunately I'm a bit out of my depth to make sense of that (though I'm working on it).
Also - the JavaScript code that has successfully worked via the things network uses to decode the payload from the board is here.
Does anyone know how I can get this serial output into the proper format to use in node.js?
It looks like many of the smaller/older boards this software interfaces with use baud 9600, but line 98 of main.cpp specifies a baud rate of 115200 for the debug messages:
// setup debug output or silence device
#if (VERBOSE)
Serial.begin(115200);
esp_log_level_set("*", ESP_LOG_VERBOSE);
I suspect switching to a baud rate of 115200 will help:
const serialPort = new SerialPort({
path: "COM4",
baudRate: 115200,
autoOpen: false,
});
If that doesn't do the trick, you can make sure the other serial parameters match those set in main.cpp, starting at line 394. UART0 is the one that emits the log messages on the ESP:
static void ble_spp_uart_init(void)
{
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_RTS,
.rx_flow_ctrl_thresh = 122,
.source_clk = UART_SCLK_DEFAULT,
};
...
Looking at the API, you could specify the other parameters like so:
const serialPort = new SerialPort({
PATH: "COM4"
baudRate: 115200,
databits: 8,
parity: false,
stopbits: 1,
});
though I'm not quite sure I understand how or where it is sending them via serial
The ESP_LOG functions are really just special wrappers around vprintf. vprintf normally writes to stdout by default but the ESP redirects that to a dedicated UART (serial port). Check out the source:
static vprintf_like_t s_log_print_func = &vprintf;
void esp_log_writev(esp_log_level_t level,
const char *tag,
const char *format,
va_list args)
{
if (!esp_log_impl_lock_timeout()) {
return;
}
esp_log_level_t level_for_tag = s_log_level_get_and_unlock(tag);
if (!should_output(level, level_for_tag)) {
return;
}
(*s_log_print_func)(format, args);
}
That UART handles the encoding and buffers required to transmit over the serial port.
You need to check following things :
Check if baud rates of both the esp32 and node.js are same - most of the time garbage data received on COM if COM port configuration is not done properly.
Need to check, what data you are expecting and what is the format -is it in text (utf8) format or some binary format ? Accordingly you need to parse the out put.
It would be clear once you post a sample data the esp32 is sending and the buffer you are receiving on Node.js code.

Struggling to get ESP8266 on Arduino Uno working reliably with AT communication

I am struggling to get ESP8266 connected to an Arduino Uno working reliably as a webserver. The firmware of my ESP8266 is 1.1.1 - I don't have the option (or knowledge) to update it at the moment. Below is my code. It works, barely, if I serve a small string. However, it usually closes the connection or just loads forever (crashes?) if I try to load the page from the browser three or four times. Ultimately I need to serve a webpage with json embedded in it that will load a second page served by the esp8266, a json file. I have a working demo of that but it crashes after a few retrievals. I understand that my html page is too long for strings so have been attempting to shift across to PROGMEM, initially testing with just a short string. I am storing and retrieving that correctly (I think, at least I can Serial.print it) but as soon as I try to write it to the ESP8266 I get a never ending load in my browser.
Where am I going wrong here? Is it the string/PROGMEM that is causing the issues or is there something else I'm missing in the AT commands (like some sort of ping to keep the connection open)?
//load softserial library
#include <SoftwareSerial.h>
#include <avr/pgmspace.h>
//set a boolean constant variable to true
//#define DEBUG true
const boolean DEBUG = true;
//RX (pin 2) goes to TX on esp8266, TX (pin 3) goes to RX on esp8266
SoftwareSerial esp8266(2, 3);
//input from the photoresistor
//int photoresistorpin = 0;
//create a PROGMEM variable
//String WEBPAGE = "hello";
static const char PROGMEM WEBPAGE[] = {"hello"};
/*
static const char WEBPAGE[] PROGMEM = R"rawliteral(
<html>
<head>
<meta name="viewport" content="width=device-width, minimumscale=1, maximum-scale=1, initial-scale=1">
</head>
<h1>Light:</h1><div id="light"></div>
<script>
function loadDoc()
{
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200)
{
var obj = JSON.parse(this.responseText);
document.getElementById('light').innerHTML = obj.data[0].datavalue;
}
};
xhttp.open('GET', 'data.json', true); xhttp.send();
}
var timedEvent = setInterval(function() { loadDoc(); }, 5000);
</script>
</body>
</html>
)rawliteral";
*/
//const int WEBPAGE_len = sizeof(WEBPAGE)/sizeof(WEBPAGE[0]);
void setup()
{
//open the serial port
Serial.begin(115200);
//print setup started in the serial monitor
Serial.println("Setup started");
//start esp8266 module (note: your esp's baud rate might be different)
esp8266.begin(115200);
//reset esp8266 module
senddata("AT+RST\r\n", 2000, DEBUG);
//set esp8266 as access point mode
//1 = Station mode (client)
//2 = Access point mode (host)
//3 = Access point mode + Station mode
senddata("AT+CWMODE=2\r\n", 1000, DEBUG);
//get ip address for esp8266
senddata("AT+CIFSR\r\n", 2000, DEBUG);
//configure esp8266 for multiple connections
senddata("AT+CIPMUX=1\r\n", 1000, DEBUG);
//turn on esp8266 server on port 80
senddata("AT+CIPSERVER=1,80\r\n", 1000, DEBUG);
//setup completed
Serial.println("Setup done");
}
void loop()
{
//take a reading from the photoresistor
//int lightval = analogRead(photoresistorpin);
int lightval = random(1000);
//to test
//Serial.println(lightval);
//is the esp8266 sending a message
if (esp8266.available())
{
//if received data from esp8266
if (esp8266.find("+IPD,"))
{
//subtract 48 because the read() function returns the ASCII decimal
//value and 0 (the first decimal number) starts at 48
int connectionid = esp8266.read() - 48;
//Serial.println("");
//Serial.println("*****");
//Serial.print("string = ");
//read the url sent by the client, look for the variable (/)
String msg;
esp8266.find("/");
delay(100);
msg = esp8266.readStringUntil(' ');
String pathrequested = msg.substring(0);
Serial.println("*****");
Serial.println(pathrequested);
Serial.println("*****");
//create a senddata string to send the webpage to the esp8266
String cipsend = "AT+CIPSEND=" + String(connectionid) + ",";
//cipsend += WEBPAGE.length();
cipsend += strlen_P(WEBPAGE);
cipsend += "\r\n";
Serial.println(cipsend);
char buffer[1000];
strcpy_P(buffer, WEBPAGE);
Serial.println(buffer);
//senddata(cipsend, 500, DEBUG);
//senddata(WEBPAGE, 500, DEBUG);
senddata(buffer, 500, DEBUG);
//create a string closecommand with the connection id and send it
String closecommand = "AT+CIPCLOSE=" + String(connectionid) + "\r\n";
senddata(closecommand, 500, DEBUG);
//increment the count
//count++;
}
}
}
void senddata(String command, const int timeout, boolean debug)
{
//send the received command to the esp8266
esp8266.print(command);
//set int variable to the number of millisends since Arduino began
long int time = millis();
//while the time and the timeout is less than the number of millisends since Arduino began
while((time + timeout) > millis())
{
//while the esp8266 is sending messages
while(esp8266.available())
{
//display output in the serial window
Serial.write(esp8266.read());
}
}
}
Assuming that "get a never ending load in my browser" means no display in the browser - check the following:
1. Get rid of String amd String constructors (+=) in your code and replace it with a fixed char array for the building of messages. Read more: https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/
2. My experience with the AT interface was - more than 9600 baud is not reliable and this is not sufficient for doing what you want.
3. If your Esp module has min 512kb (most likely up to 4Mb) host your code there and use the UNO only as sigmal receiver/sender from the attached hardware/ sensors. Save yourself a lot of trouble and problems - most of the examples with AT com are not really working and more of a pain in the ***. I ditched the AT interface within 2 days and never in the last 4 years missed anything. By flashing code to the Esp module you also have full control and visibility on whats going on due to the debug possiblitie AND you can even host html/css/js on the File system there (LittleFS / SPIFFS)

Configuring and pairing 2 HC-06 Bluetooth modules as Master and Slave using Arduino UNO

I have been trying to establish connection between two HC-06 Bluetooth modules. Pairing has been done. The two modules are communicating. My aim is to send a letter from one module and receive acknowledgment from the other module. The code for the master module is below.
#include <SoftwareSerial.h>
SoftwareSerial BTserial(2,3); // RX, TX
char c;
char s[]="Matched";
int t[]="NotMatched";
void setup()
{
// start the serial communication with the computer
Serial.begin(9600);
Serial.println("Arduino with HC-06 is ready");
// start communication with the HC-06 using 38400
BTserial.begin(38400);
Serial.println("Bluetooth serial started at 38400");
}
void loop()
{
// Read from HC-06 and send to Arduino Serial Monitor
if (BTserial.available())
{
c=(BTserial.read());
if (c=='a')
{
Serial.write(s);
}
else
{
Serial.write(t);
}
}
// Read from Arduino Serial Monitor and send to HC-06
if (Serial.available())
{
c = Serial.read();
Serial.write(c);
BTserial.write(c);
}
}
Similar code is used for the slave module. Except for the 'else' part in the code everything runs right. I receive acknowledgement along with the else portion being printed twice for both the if and else portion of the code i.e 'matched not matched not matched' is printed when it receives char 'a' and 'not matched not matched not matched' is printed when it receives anything other than 'a' . Can you please give me suggestions on what could be wrong.
Have you printed the characters that you are reading?
I had a similar problem and I found that the Bluetooth was receiving garbage characters. The reason was because the standard baudrate, of HC-06 modules, is 9600, so if you change:
BTserial.begin(38400);
to
BTserial.begin(9600);
In both master and slave, it might work.

Arduino wireless and Node.js

I'm working on an Arduino project to control motors and read sensors. I decided to use the web view using Node.js as a medium channel to read/write from the serial port to the browser using either libraries (SerialPort and SerialPort2).
Both are working fine when I connect the Arduino directly to the USB device using a wire, but Node.js can't seem to read anything when I connect the Arduino to the USB device through my wireless adapter** (APC220) even though I can read everything received on it using the Arduino serial monitor.
I checked every possible reason behind that; I checked the baud-rate I'm using for the Arduino communication with the wirelss serial and the APC220 and the bridge connector (USB-to-serial converter). They all have the same settings: 9600 baud-rate, no parity /flowcontrol, data bits: 8 , stop bits: 1.
The behavior is as follows. It connects to the COM port without trouble, and then I tried printing the errors, but it seems there are none identified by either SerialPort libraries. Then no reading comes to the event (data), which means it (Node.js) is not interacting with the serialport even though it is open.
Note:
I know I can use another Arduino as a medium between the USB port and the wireless adapter, but I want to understand this problem and solve it cleanly without such work around.
What could the problem be?
server [node.js]:
var SerialPort = require('serialport2').SerialPort;
var portName = 'COM15';
var io = require('socket.io').listen(8000); // Server listens for socket.io communication at port 8000
io.set('log level', 1); // Disables debugging. This is optional. You may remove it if desired.
var sp = new SerialPort(); // Instantiate the serial port.
sp.open(portName, { // portName is instatiated to be COM3, replace as necessary
baudRate: 9600, // This is synchronised to what was set for the Arduino code
dataBits: 8, // This is the default for Arduino serial communication
parity: 'none', // This is the default for Arduino serial communication
stopBits: 1, // This is the default for Arduino serial communication
flowControl: false // This is the default for Arduino serial communication
});
io.sockets.on('connection', function (socket) {
// If socket.io receives message from the client browser then
// this call back will be executed.
socket.on('message', function (msg) {
console.log(msg);
});
// If a web browser disconnects from Socket.IO then this callback is called.
socket.on('disconnect', function () {
console.log('disconnected');
});
});
var cleanData = ''; // This stores the clean data
var readData = ''; // This stores the buffer
sp.on('data', function (data) { // Call back when data is received
readData = data.toString(); // Append data to buffer.
// If the letters '[' and ']' are found on the buffer then isolate what's in the middle
// as clean data. Then clear the buffer.
console.log(readData); // **Here you should be able to print the data if you receive any**
if (readData.indexOf(']') >= 0 && readData.indexOf('[') >= 0) {
cleanData = readData.substring(readData.indexOf('[') + 1, readData.indexOf(']'));
readData = '';
console.log("-- "+cleanData);
io.sockets.emit('message', cleanData);
}else if(readData.indexOf('[') >= 0){
cleanData = readData.substring(readData.indexOf('[') + 1, readData.length);
readData = '';
}else if(readData.indexOf(']') >= 0){
cleanData += readData.substring(0, readData.indexOf(']'));
readData = '';
console.log("-- "+cleanData);
io.sockets.emit('message', cleanData);
}else{
cleanData += readData;
readData = '';
}
//console.log(readData);
//io.sockets.emit('message', readData);
});
While the monitor is running no other program can read the serial port.
In case you do not open both at the same time then things are more tricky. My suggestion would be to spy on the wire. That is: install Wireshark and have a look at the data on the serial connection / USB bus.
You might also want to check how the serial port of the APC220 and the Arduino differ with regard to their serial/USB converters. Another idea would be to analyze this issue under Linux since may allow more insights into the low-level differences of the chip sets / USB activity. Of course if you do not have Linux experience this is hard to do, but maybe you know some Linux enthusiasts.
Well, both your codes look all right, so I'm pretty sure your problem is something obvious (like the nose in the middle of your face) that you don't see because you're too focused on details. So here's a checklist I'd do first:
Are you sure your serial interface is the COM15, and never changes?
Are you sure both APC devices have correct baudrate configured?
Did you try making your Arduino send a simple code that sends the same thing over the channel?
Like:
void loop() {
...println("TEST");
delay(1000);
}
And on your host:
sp.on('data', function (data) {
console.log(data.toString());
});
When you get something buggy in your system, try to build the most simple use case of that buggy part, so you're sure that's nothing else in your codes that interferes with that. You don't need to make your Arduino work on the GPS stuff, as well as your Node.js stuff work on the web stuff.
Just make it the most simple as you can. (And don't forget to add a delay in your Arduino loop, or you may have difficulties reflashing the chip).
You may also want to add to your code the error catching part of serialport2:
port.on('error', function(err) {
console.log("ERROR receiving serial data: ", err);
});
As well as for your open() statement:
sp.open(portName, portConfig, function (err) {
console.log("ERROR opening serial port: ", err);
});
As you may be missing error reporting on the host side!

Resources