WebSocket Server

Posted on
  • Hi,

    Just to say that the latest builds of Espruino now support WebSocket server in JS. Not only that, but mixed WebSocket and HTTP server!.

    For instance:

    page = '<html><body><script>var ws;setTimeout(function(){';
    page += 'ws = new WebSocket("ws://localhost:8000/socketser­ver", "protocolOne");';
    page += 'ws.onmessage = function (event) { console.log("MSG:"+event.data); };';
    page += 'setTimeout(function() { ws.send("Hello to Espruino!"); }, 1000);';
    page += '},1000);</script></body></html>';
    
    function onPageRequest(req, res) {
      if (req.headers.Connection=="Upgrade") {    
        var key = req.headers["Sec-WebSocket-Key"];
        var accept = btoa(E.toString(require("crypto").SHA1(k­ey+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11­")));
        res.writeHead(101, {
            'Upgrade': 'websocket',
            'Connection': 'Upgrade',
            'Sec-WebSocket-Accept': accept,
            'Sec-WebSocket-Protocol': req.headers["Sec-WebSocket-Protocol"]
        });
        var ws = require("ws")(undefined,{
          serverRequest : req,
          serverResponse : res
        });
        ws.on('message',function(msg) { print("MSG:"+msg); });
        ws.send("Hello from Espruino!");
      } else {    
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.end(page);
      }
    }
    
    require('http').createServer(onPageReque­st).listen(8000);
    

    I had to tweak the WebSocket library a bit, but it hopefully at some point the code above can mostly be rolled into the library and you'll be able to do something like:

    function onPageRequest(req, res) {
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.end(page);
    }
    
    require('ws').createServer(onPageRequest­).listen(8000);
    
  • Ok, just changed so the following works:

    var page = '<html><body><script>var ws;setTimeout(function(){';
    page += 'ws = new WebSocket("ws://" + location.host + "/my_websocket", "protocolOne");';
    page += 'ws.onmessage = function (event) { console.log("MSG:"+event.data); };';
    page += 'setTimeout(function() { ws.send("Hello to Espruino!"); }, 1000);';
    page += '},1000);</script></body></html>';
    
    function onPageRequest(req, res) {
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.end(page);
    }
    
    var server = require('ws').createServer(onPageRequest­);
    server.listen(8000);
    server.on("websocket", function(ws) {
        ws.on('message',function(msg) { print("[WS] "+JSON.stringify(msg)); });
        ws.send("Hello from Espruino!");
    });
    

    All updated and documented here: http://www.espruino.com/ws

  • Very nice!
    Sadly, trying to load this on the esp8266 results first in an error because the crypto module isn't available and then an out of memory error.
    Can you figure out the low memory mark on some target where it does actually load? I'm wondering whether the esp8266's 1023 JSvars are 10% off or way off.

  • It uses 1924 vars (@16b/var) when doing this using ESP8266 with AT commands.

    BUT: even just connecting to the network (without any WebSockets) uses 1305 vars with ESP8266, so I'd say you're probably not that far off being able to make this work.

  • Hi.

    I tried that code, but i just recieve unreadyable data at the server.

    ws.on('message',function(msg) { print("[WS] "+JSON.stringify(msg)); });
    

    The result in the web-ide is like that:

    [WS] "\xC7\xD3\x00\x00\xC7\xD3\x00\x00\xC7\xD­3"
    [WS] ""
    [WS] "\x1A\t\x00\x00\x1A\t\x00\x00\x1A\t"
    [WS] ""
    [WS] ""
    [WS] "/<\x00\x00/<\x00\x00/<"
    [WS] "bl\x1C\x00bl\x1C\x00bl"
    [WS] "R\x9E\xEF\x00R\x9E\xEF\x00R\x9E"
    [WS] "<C\x00\x00<C\x00\x00<C"
    [WS] "\xE9\xBC\x00\x00\xE9\xBC\x00\x00\xE9\xB­C"
    

    That should be always the same message...

    ws.send("hallo welt");
    

    What is wrong with the code? I run it with the pico VERSION 1v85 in combination with the esp8266.
    I hope someone can help me with that.

    In addition the connection interrupt all the time. Is there an easy solution for a stable connection? I want to send a lot of data from client to the server.

    FullCode:

    Serial2.setup(9600, {    rx: A3,    tx: A2}); 
    var wifi = require("ESP8266WiFi").connect(Serial2, function(err) {
        if (err) throw err;
        wifi.reset(function(err) {
            if (err) throw err;
            console.log("Connecting to WiFi");
            wifi.connect("SSID", "12345", function(err) {
                if (err) throw err;
    
                var server = require('ws').createServer(onPageRequest­);
                server.listen(8000);
                server.on("websocket", function(ws) {
                    ws.on('message',function(msg) {
                      print("[WS] "+JSON.stringify(msg));
                    });
                    ws.on('open', function() {
                      ws.send("Connected to server!");
                    });
                    ws.send("Hello from Espruino!");
                });
            });
        });
    });
    var page = '<html><head><meta charset="utf-8"><title>WebSocket Client Test...</title></head><body><script>var ws;setTimeout(function(){';
    page += 'ws = new WebSocket("ws://" + location.host + "/my_websocket", "text");';
    page += 'ws.onmessage = function (event) { console.log("MSG: "+event.data); };';
    page += 'setTimeout(function() { ws.send("Hello to Espruino!"); }, 1000);';
    page += '},1000);</script></body></html>';
    page += '</script></body></html>';
    function onPageRequest(req, res) {
        res.writeHead(200, {        'Content-Type': 'text/html'    });
        res.end(page);
    }
    

    In Browserconsole (Chrome) i entered "ws.send(hallo welt)".

    Thanks.

  • How stable is it when you're just getting webpages with normal HTTP?

    It could actually be a problem with your wiring... The ESP8266 draws quite a lot of power when it's going, and if the connections aren't good it can cause a lot of unreliablility, and I guess potentially the corruption you are seeing.

  • No, you're right - I just tested here and got the same.

    I think the unreliability could still be wiring - sometimes adding a capacitor across ESP8266's power helps.

    The corruption seems to be related to Espruino getting split packets from the ESP8266. It gets the start of the data packet, but not the rest - what you're seeing is the 4 'mask' bytes repeated over and over. I'll see what I can do to fix that now.

  • Ok, try now - the corruption should now be gone at least.

  • Next post...

  • Great to hear from you. Thank you for your response!

    Now it seems to work 95% :)

    Some of my tests:

    [WS] "hallo welt"
    [WS] "hallo welt 123"
    [WS] "123"
    [WS] "hallo welt 123"
    [WS] "[object Object]"
    [WS] "test"
    [WS] "{\"room\":\"room\",\"msg\":\"message\"}­"
    1: [WS] "\x14"
    2: [WS] "PUM\x1F\x1D\x00\x02O^M\x02\x1E\x15MUO\x­1F\n\x1C\x1E\x13\b\nO\x0Fe\x8Ah\"\xC9\x8­F\x13\x00\xBB\xE0\aO\xEB\xB5JP\xA6\xE0\x­05\x00\xE5\xAD\x05Q\xAE\xADR\x00\xA4\xEA­\x1BQ\xA8\xE8\r\x00\xB4\x94%Nw\x83y5U\xF­1\x16!\x1A\xA1Cl\x05\xEC\x16#U\xAF[#\x04­\xE4[tU\xEE\x1C=\x04\xE2\x1E+U\xFE;0=\x1­8=\xDAF:O\xB5Ru\x1F\xE0\x1FjR\xB5"
    [WS] "{\"room\":\"room\",\"msg\":\"message\"}­"
    [WS] "{\"room\":\"room\",\"msg\":\"message\"}­"
    [WS] "{\"room\":\"room\",\"msg\":\"message\"}­"
    

    The named lines (1,2) should be also the same message as before. My conclusion is, that i still get that "unreadable" data, if i wait a little bit.

    Start the WebSocket and send a Message -> OK
    Send more messages -> OK
    Wait a minute and send one message -> Unreadable Data
    send more messages -> Sometimes OK, timesomes unreadable
    send more messages -> everything OK

    So always if i wait a little bit it seems that the next data package can't processed successfully.

    If i wait for 5-10 Minutes and try to send a message from Chrome:

    WebSocket is already in CLOSING or CLOSED state.
    

    I would be really happy if you could check that again :)
    I will also try the capacitor for the ESP8266.

    Thank you!

    Edit: I looked at the ws.js file. Why you don't allow to send data bigger then 125 character? How can i send more than 125? I need to send more than 300 characters.

  • @user65754

    The current implementation is limited to 125 chars. To use larger the module would be need to be implemented to split the data over multiple packets which complicates things quite a bit.

    Do you have a sample of the data you want to send? There might be a way of reducing the amount of data, especially if there are large text descriptors in the data. You can also store the data in a struct, and the convert that to json to send. The json can be self describing, so you could split your message into chunks that are under the 125 byte limitation.

  • I try to stream video data to the server to control 100 ws2812 leds.
    I tried to work with 1byte for each pixel, so the current limitations do not disturb.

    But i get no stable connection. Always if i send between 25 and 60 messages i get:

    WebSocket is already in CLOSING or CLOSED state.
    

    Would be really good so solve this problem first ;) If i couldn't get a reliable connection, i can't use that websocket implementation...

    Please have a look at it. Thanks.

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

WebSocket Server

Posted by Avatar for Gordon @Gordon

Actions