Avatar for jgrizou

jgrizou

Member since Mar 2021 • Last active Sep 2021
  • 2 conversations
  • 16 comments

Most recent activity

  • in JavaScript
    Avatar for jgrizou

    Nothing new on that front yet but I just found out about https://www.npmjs.com/package/proxy-deep­. Posting here to keep track.

  • in JavaScript
    Avatar for jgrizou

    Thanks fo the feedback!

    Object.keys(global)

    Yes! for (a in global) { console.log(a, "is a", typeof eval(a)) }. I will have a think if it makes sense to use this instead.

    Good point about eval(undefined). Does this actually fail, or is it that accessing a variable that doesn't exist is causing a reference error?

    I meant UART.eval('functionwithnoreturnstatement­()', cb), will try to evaluate the result of the function call on the device, get undefined back, then try to interpret is as a JSON (https://github.com/espruino/EspruinoWebT­ools/blob/13032d0e862d9976ed5eed33b42f07­e93e6c25c3/uart.js#L492). It will fail, be send to the catch, and call the callback with null (https://github.com/espruino/EspruinoWebT­ools/blob/13032d0e862d9976ed5eed33b42f07­e93e6c25c3/uart.js#L496). So we cannot make the difference between a successful call to a real function and a call to something that does not exist or failed to execute properly.

    In other words, in the example above, await proxymiseRobot.toggle() will return null, instead of undefined.

    This try/catch mechanism is great when we got an error and should be kept, but would be nice to have a third case for undefined like:

    if (d.trim() == "undefined") {
       cb(undefined)
    } else {
     // do what is already being done
    }
    

    but you might be able to make get return a function, but with a valueOf method

    Do you mean something like this?

    var a = function() { return 12;}
    a.prototype.valueOf = function() { return 42;};
    console.log(a)  // would like 42, got function() { return 12;}
    console.log(a()) // would like 12, got 12
    

    Would be perfect indeed, but does not seem to work for functions.

  • in JavaScript
    Avatar for jgrizou

    I might have found a way around my problem with an additional call eval('typeof prop') to check if the property exist and is a function or not.

    Ok that approach work. It is a tricky code with a few promise and using https://github.com/kozhevnikov/proxymise­ on top.

    Code is very rough right now, just working my way around things. But, if curious, for now code is here: https://editor.p5js.org/jgrizou/sketches­/Si31amD_p (see robot.js and sketch.js) and testable at https://editor.p5js.org/jgrizou/present/­Si31amD_p

    For example, if you have a espruino device with a code like:

    var speed = 0.5;
    
    var on;
    function toggle() {
      on = !on;
      digitalWrite(LED1, on);
    }
    
    function add(x, y) {
      return x+y;
    }
    

    You can load this page https://editor.p5js.org/jgrizou/present/­Si31amD_p, click connect button and connect to the device.

    Then in the webbrowser console the following commands should work:

    await proxymiseRobot.speed
    // 0.5
    await proxymiseRobot.toggle()
    // light should toggle
    await proxymiseRobot.add(2,2)
    // 4
    

    A lot of cleaning, refactoring, bulletproofing is required, but the conceptual basis are there and it seems to work so I have hope, see head of sketch.js at https://editor.p5js.org/jgrizou/sketches­/Si31amD_p.

    That was fun anyway! I will try to handle the set route in the proxy too.

    In time, I will make it a standalone and actually usable library but for now I am exploring.

  • in JavaScript
    Avatar for jgrizou

    Thanks @Robin

    what you are after?

    Imagine we have this code on the device:

    var speed = 0.5;
    function move(arg) {
     // do something with arg
    }
    

    I am trying to create a robot object in the webbrowser that is connected to the device via UART, such that robot.speed translate into a call to UART.eval('speed'), and robot.move(value) translate to call to UART.eval('move(value)'). But in a generic way, so that the object robot does not really have the properties speed and move and any other properties could be called without defining them explicitly, hence the use of Proxy as per Gordon suggestion.

    Check again the first few posts for more details. I hope that makes some sense.

    ==

    I might have found a way around my problem with an additional call eval('typeof prop') to check if the property exist and is a function or not.

  • in JavaScript
    Avatar for jgrizou

    I am banging my head trying to make proxy work for all cases which seems very hard, if not impossible. Ideally I would like both get, set, and apply to work, so we can do:

    robot = EspruinoDevice(UART) 
    var p = await robot.speed;  // assuming speed is a variable defined on the repl
    var temp = await robot.getTemperature() // assuming getTemperature() is defined on the repl
    await robot.move(someparameters)
    await robot.speed = 2*p; // changing the speed variable
    

    The problem I am having is knowing if speed or move are object or function which change the expected behaviour from the proxy. I tried many approaches, but I start to feel it is impossible because we can only know if it is a function or the object after we return something and see if it is later called as a function again. I then tried to go via promises to see if I could decide this later but the same problem came back in the end. I am running short of ideas right now.

    Some ressources I used:

    I am quite stuck so I will stop now. I am aware all can be solved by relying on setter and getter function on the device, e.g getSpeed() and setSpeed(), and then building the proxy assuming all get calls are function calls. But I enjoy the challenge, it would be so neat to get all cases working seamlessly.

    Any thoughts on this?

    As an alternative route, is there a method to list all user defined variable and function on the Espruino device? That way we could ask for that list when connecting and decide what can and cannot be called.

    ==

    One learning to maybe add to the issue -> it would be good to have the eval function return 'undefined' when it receives 'undefined' (right now it catch an error, print it, and call the cb with null instead). This way we can use eval for all actions and know if it actually crashed or ran well but got undefined back. That would be around here: https://github.com/espruino/EspruinoWebT­ools/blob/13032d0e862d9976ed5eed33b42f07­e93e6c25c3/uart.js#L491-L497

    Also I implemented a simple promise system on top of eval, works very well!

  • in JavaScript
    Avatar for jgrizou

    Quick update. I got UART.write, UART.eval, and a custom UART.on('myevent', callback) all working simultaneously.

    When I register a customconnection.on('data', ...) callback, it overwrites the on('data', ...) callback defined within UART.write (see https://github.com/espruino/EspruinoWebT­ools/blob/13032d0e862d9976ed5eed33b42f07­e93e6c25c3/uart.js#L470-L474), so I had to copy those few lines back into my custom one. A bit hacky as I inject data back into the connection from the outside.

    Code is very rough right now, just working my way around things. But, if curious, for now code is here: https://editor.p5js.org/jgrizou/sketches­/Si31amD_p (see robot.js and sketch.js) and testable at https://editor.p5js.org/jgrizou/present/­Si31amD_p

    Next I will try the proxy trick :)

  • in JavaScript
    Avatar for jgrizou

    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.

  • in JavaScript
    Avatar for jgrizou

    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

  • in General
    Avatar for jgrizou

    Obviously for most people, if your web browser asks for Bluetooth permissions you click 'Hell No' without even batting an eyelid. When you finally do get a bluetooth device you want to use with the web browser, clicking that button could have happened over a year ago alongside a barrage of other questions about app permissions :)

    That is for sure what happened here ;)

Actions