Pico communication with Node.js over USB

Posted on
  • Hello,

    I've managed to hack my way to a solution for my project, but just hoping for some guidance from experts if this is the best way to do this. This is my first experience with microcontrollers and serial communication.

    I have an Espruino Pico with a BME280 attached, connected to a host computer via USB.

    I'm looking for a stable/energy efficient solution where I can run Node.js on the host, and grab sensor values from the Pico once a minute (currently 5 seconds while testing).

    Code on the Pico:

    var i2c = new I2C();
    i2c.setup({ scl: B6, sda: B7 });
    var bme = require("BME280").connect(i2c);
    

    Currently my best try on the Node.js code:

    const { spawn } = require('child_process');
    
    setInterval(callPico, 5000)
    
    function callPico() {
      const pico = spawn('espruino', [
        '--port', '/dev/tty.usbmodem00000000001A1',
        '--board', 'PICO_R1_3',
        '-e', 'console.log(bme.getData())',
        '--quiet'
      ])
    
      pico.stdout.on('data', (data) => {
        const line = data.toString().trim()
        if (
          line !== ''
          && line !== 'Explicit board JSON supplied: "PICO_R1_3"'
          && line !== 'Upload Complete'
        ) {
          const json = JSON.parse(line)
          console.log({
            temperature: json.temp,
            humidity: json.humidity
          });
        }
      });
    
      pico.stderr.on('data', (data) => {
       console.error('ERROR:', data.toString());
      });
    }
    

    I also tried using the espruino node package like this:

    var esp = require("espruino");
    const PORT = '/dev/tty.usbmodem00000000001A1'
    esp.expr(PORT, 'bme.getData()', console.log);
    

    Which does eventually return the sensor values, but it spams the log with 100+ lines output (too many to copy/paste here!) and the process fails to exit, something to do with Noble scanning.

    Is there a better approach? Thanks for your help.

  • Hi! Glad you got something working! Personally I think there is a tidier way of getting it going though - it's to let the Pico collect the data and push it out itself, then to just listen to the USB serial port for data.

    So I'll just use temperature from the chip as anyone can try that - but all you need to do is replace E.getTemperature() with bme.getData():

    // push data every 2 seconds
    setInterval(function() { 
      USB.println(E.getTemperature()); 
    }, 2000)
    

    Now you can just do cat /dev/tty.usbmodem00000000001A1 on the host PC and it'll display data.

    Now you might just be able to open that as a file in Node.js, or potentially you can use child_process(https://nodejs.org/api/child_process.htm­l) to run cat /dev/tty.usbmodem00000000001A1 and respond when you get data from it: https://nodejs.org/api/child_process.htm­l#child_process_child_process_spawn_comm­and_args_options

    const { spawn } = require('child_process');
    const ls = spawn('cat, ['/dev/tty.usbmodem00000000001A1']);
    
    ls.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`); // your data comes in here
    });
    
    ls.stderr.on('data', (data) => {
      console.error(`stderr: ${data}`);
    });
    
    ls.on('close', (code) => {
      console.log(`child process exited with code ${code}`);
    });
    
  • Many thanks for the reply Gordon.

    That does seem nice and neat. I didn't find the USB class before (https://www.espruino.com/Reference#l__gl­obal_USB).

    When I try:

    cat /dev/tty.usbmodem00000000001A1
    

    I'm not getting any output - just blank. However when I connect to the board with:

    espruino --board PICO_R1_3 --port /dev/tty.usbmodem00000000001A1
    

    I see a log of correct values there. Any ideas why no output from cat?

    Pico code:

    var i2c = new I2C();
    i2c.setup({ scl: B6, sda: B7 });
    var bme = require("BME280").connect(i2c);
    
    setInterval(() => {
      USB.println(JSON.stringify(bme.getData()­));
    }, 5000)
    

    Thanks again.

  • I guess from the port string you're on a Mac? Maybe it works differently to Linux..

    Do you have something like /dev/cu.usbmodem00000000001A1? Could you try cating that?

  • Thank you, it's working perfectly now.

    I'd Googled and read about the difference between tty and cu (https://stackoverflow.com/questions/8632­586) and thought I'd picked the right one for this use case but now I don't think I really understand it... anyway, if it works it works!

    I have one more general question if you don't mind:

    I landed on the Pico as it's very small and can be connected via Ethernet using the Wiznet W5500 board. I have ~10m Cat6 cable in my wall. I'd been planning to connect this to the W5500 and run custom 5V power through the Cat6 cable for the Pico. However it's recently occurred to me that I could terminate the cable with 4-wire USB and 4-wire Ethernet and instead talk to the Pico entirely over USB (in my setup it's no problem connecting Pico to a router or to an always-on host computer). Do you have any thoughts on the pros and cons of each approach? Would one be more stable and/or power efficient than the other? The Pico's only job would be to send sensor data once a minute back to the host (or via MQTT using W5500) as above.

    Many thanks, Dave

  • 10m for USB would way too long. IIRC max cable length for USB 2.0 is 5m. But you might get lucky, and may work. Keep us posted :)

  • Thanks for the advice.

    I read this page which gave me hope: http://www.yourcablestore.com/USB-Cable-­Length-Limitations-And-How-To-Break-Them­_ep_42-1.html#usbethernet but after some more research I think they are referring to active USB-to-Ethernet adapters not simply using ethernet cables with USB terminations!

    I think I'll still terminate my cable with 4-wire USB and 4-wire ethernet on each end, then I can easily test if it works and if not (hopefully) still use the USB side for 5V power to the Pico!

  • Sounds like a plan - please let us know how you get on. It'd be really interesting to see if USB will work over that distance!

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Pico communication with Node.js over USB

Posted by Avatar for daviestar @daviestar

Actions