Brainstorming uart.js functionalities

Posted on
  • Hi Gordon, all,

    I started playing making a robot controlled via a webpage using Espruino, see photos attached and video here: https://youtu.be/xKEqqFrYgNQ

    Building the robot took a few hours. And both embedded code + remote control via basic webluetooth page using uart.js less than one hour, I really didn't expect it would be so quick to get a MVP, the Espruino toolchain and REPL spirit is amazing. See very basic interface here: https://editor.p5js.org/jgrizou/present/­osAAXLUtL. It also seem that I could connect several webpage to the same robot which is quite cool!

    This was mind blowing to me on two aspects:

    • the ease of uploading code to a robot via the WebEditor
    • the ease of simply defining function in the embedded REPL that we can call directly from the uart.js library. No interface or protocol to define and deal with, it is just great!

    So first, thanks for developing all this!

    --

    I would like to brainstorm uart.js extension ideas here and collect the community opinion as to wether it is technically feasible and where I should start to implement it if I wanted to.

    At the moment, I can see two ways to use the UART, write and eval:

    • UART.write('LED1.set();\n');
    • UART.eval('E.getTemperature()', function(t) { // do something with t });

    And my understanding is that eval is calling write with an eval statement "\x10eval(process.env.CONSOLE).println(J­SON.stringify('+expr+'))\n". I not 100% sure how this work but it makes sense.

    Source code here: https://github.com/espruino/EspruinoWebT­ools/blob/master/uart.js

    --

    I would be interested in:

    1) The ability to publish information from the embedded device to the webpage. For example, I might want to send an event if a sensor changes value, say my robot bumped into an object. Ideally, we would be able to a callback in uart.js for all spontaneous incoming messages. And the user can then sort them as they wish.

    Maybe via a function sendToUart(), which can be tested using something like:

    setInterval(function() {sendToUart({'value': true}}), 500);
    

    By doing setInterval(function() {console.log({'value': true}}), 500);, I could see the packet being sent to the webpage but they would need to be processed and formatted. It might also make it harder to differentiate between self-published messages and messages sent after an eval() was called maybe. Althought eval() calls seemed to work well despite that noise.

    Just to be clear, I am interested in self-published events from the robot. That is I want to avoid having to call eval() from the browser at fixed interval.

    2) The ability to use an embedded device as if it was a javascript module. This is mostly to avoid having to use string calls in the write and eval function. That would require having an additional function that, on uart.js connection, could read all function available on the embedded device and publish them under an object so we could do something like this on the webpage:

    var robot = UART.connect()
    robot.left();
    var temp = robot.getTemperature();
    

    In the background, all these call would use uart.js write and eval function. Function to be published could be made explicit via some sort of export statement in the embedded code like:

    exportUart({stop, left, right})

    Similar to module export in javascript.

    --

    Do you have thought on this? To be clear I am not asking anyone to implement this, but rather for some comments/discussions on:

    • whether this is already possible?
    • if it is theoretically/technically possible? If yes, what approach could be used?
    • where should I look in the code and what approach should I consider if I wanted to make this happen?

    Thank you for your time reading this long post, any insight from the community would be very appreciated!

    Jonathan


    2 Attachments

    • 2021-04-08 09.53.49.jpg
    • 2021-04-08 09.54.00.jpg
  • Thr 2021.04.08

    Hi @jgrizou and Kudos on your ease of project success!

    'So first, thanks for developing all this!'

    I know that @Gordon will appreciate your kind words for all the hard work and determination he has put into the the creation and success of the Espruino project, making it's ease of use a core goal for evey newcomer.


    'The ability to publish information from the embedded device to the webpage'

    There is a great starting page tutorial with embedded 'Try Me' buttons for each snippet that demonstrate BLE communication both ways:

    note: mentally substitute 'MDBT42Q' for 'Puck.js' and use those snippets as is


    http://www.espruino.com/Web+Bluetooth

    http://www.espruino.com/Interfacing

    http://www.espruino.com/Tutorials



    I'm only able to provide some assistance using Windows10, but this page should assist visually in the connectivity part:

    http://www.espruino.com/Quick+Start+BLE



    I'll defer to Gordon for the technical explanation for the eval() funtionality, and your comments/discussions questions.

  • Hi! That looks like a really neat little robot design! Are you planning to publish it anywhere?

    The ability to publish information from the embedded device to the webpage

    That is actually possible right now. It's not well documented for UART.js, but there is an example for the Puck.js library (which is just like UART.js, except it's Bluetooth only). You basically call connect and then you get a callback whenever data is received (which you can do by calling Bluetooth.println).

    https://www.espruino.com/Web+Bluetooth#t­wo-way-communications

    or

    https://www.espruino.com/Bangle.js+Data+­Streaming

    There was some talk of whether this could be made easier though - effectively being able to register a UART.on('myevent', callback) function so you could send multiple event types without having to filter them yourself.

    The ability to use an embedded device as if it was a javascript module

    That's really neat! I guess we could have a UART object defined on the device itself, and then just query the keys for that.

    Another option is actually you can dynamically handle key accesses using Proxy: https://spin.atomicobject.com/2018/07/02­/javascript-proxy-object/

    While that won't work on Espruino, on the PC you could happily call UART.myfunction(...) and it'd translate it into a similar call:

    Espruino = {};
    Espruino = new Proxy(Espruino, {
      get: (target, prop) => function() { console.log(prop+"("+[].map.call(argumen­ts,x=>JSON.stringify(x)).join(",")+")") },
      has: (target, prop) => true
    });
    
    Espruino.test(1,2,3,"Hello",{a:42});
    // prints 'test(1,2,3,"Hello",{"a":42})'
    

    So if you call a function that doesn't exist it's no big deal - it just creates a referenceError on Espruino.

    In a way, I guess while this could be in UART.js, maybe it even makes sense to built it as a separate library on top of it, that is Espruino specific?

  • Thanks @Robin @Gordon for sharing all this, it makes total sense and sounds feasible!

    https://www.espruino.com/Web+Bluetooth#t­wo-way-communications

    I tried with good success. UART.on('myevent', callback) is a great way to implement this combined with a function on the embedded side and format events.

    I guess we could have a UART object defined on the device itself, and then just query the keys for that.
    Another option is actually you can dynamically handle key accesses using Proxy: https://spin.atomicobject.com/2018/07/02­/javascript-proxy-object/

    Amazing! The Proxy thing is great and even more hands-off for the user.

    maybe it even makes sense to built it as a separate library on top of it, that is Espruino specific?

    Understanding this better now, I agree that a separate library makes more sense. I will work on a first version and share it here when it is ready ;)

    That looks like a really neat little robot design! Are you planning to publish it anywhere?

    Thanks! It is a quick prototype but you are right, I will make a repo with some basic info (BOM, wiring, code, etc) and share it with the community.

  • That's great - thanks!

  • Hi, I have tried to work on this a bit and got confused by the use of connections in uart.js.

    I would like to use the nice utility functions UART.write() and UART.eval() but do not want them to trigger their own connect event (that is showing up the select a port screen). I would like to connect only once when the user decides to and be able to all operations from there.

    But using the connection.on("data", cb) pattern and the write() and eval() helper function from UART seems incompatible as the UART.write() and UART.eval() are using their own separate internal connection variable.

    It feels not optimal to have to duplicate that part of the code: https://github.com/espruino/EspruinoWebT­ools/blob/13032d0e862d9976ed5eed33b42f07­e93e6c25c3/uart.js#L403-L500 entirely to replicate the UART functionalities from a connection that I would open using the method described in https://www.espruino.com/Web+Bluetooth#t­wo-way-communications

    This is actually commented in the code by saying that the UART.connect function output a connection different from the one used by write() and eval(), see image attached.

    I guess my questions are:

    • Is there a way to do both these things at once? For example adding a custom connection.on("data", cb) on the same connection used by UART.write() and UART.eval().
    • If not, because this would interfere with each others, is there a way to connect to two connections at the same time? So I could develop a tool that can use both functionalities but the user would only see one connection screen.

    If that does not work, I guess I will have to reimplement something similar to write and eval functionality but with the connection.on("data", cb) working somehow on the with it.

    I am guessing I am a bit confused with how connection works under the hood but I hope that makes some sense :)

    Thanks in advance for any guidance on that!


    1 Attachment

    • Screenshot 2021-04-20 at 22.59.36.png
  • As I understand it, UART.write/eval will create a connection (internally) and will then use that - so if you're writing to just a single device then that's all you need. You're prompted on the first call and after that it 'just works'.

    It feels not optimal to have to duplicate that part of the code:

    Yes, you're right. The write/eval there should really be some common functionality in the connection object, or at the very least should take a connection as an argument so could be used on multiple connections. Are you interested in making that change, or should I look at it?

    Is there a way to do both these things at once? For example adding a custom connection.on("data", cb) on the same connection used by UART.write() and UART.eval().

    I believe after you're connected, you can just do UART.getConnection().on('data', ...)?

  • Thanks for the feedback!

    As I understand it, UART.write/eval will create a connection (internally) and will then use that - so if you're writing to just a single device then that's all you need. You're prompted on the first call and after that it 'just works'.

    Yes. My only issue is that I want to explicitly connect to the device before sending commands, to be sure the robot is ready and two way communication is established before starting the control loops.

    I guess a work around is to trigger a connect by sending an empty UART.write('\n') and then use isConnected and getConnection. I will try and let you know how it goes!

  • I guess a work around is to trigger a connect by sending an empty UART.write('\n')

    Yes, that's what I'd do... Sometimes it's good practice to send a "\x03" (ctrl-c) anyway as if there was any command left on the REPL's input line that will clear it out

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

Brainstorming uart.js functionalities

Posted by Avatar for jgrizou @jgrizou

Actions