Search code examples
node.jsserial-portbufferiotesp32

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

  1. a messagebuffer, to store the payload
  2. a queue, as buffer for the serial data
  3. 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.


Solution

  • 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.