Arduino websocket client to a NodeJS express ws websocket server.

I have seen lots of examples of Arduinos being websocket servers, but that is not want I want. I want the online or cloud server doing all the hard work and the Arduino just responding to commands sent over the websocket. (Best if the Arduino can respond to the websocket like a chat server.)

Does anyone have any ideas?

I have a github setup for this at GitHub - hpssjellis/arduino-simple-websocket: How to connect an Arduino to a node js websocket for fast webpage to Arduino communication It contains some very old code that used to work very well.

I have posted a stack overflow question to see if I can get it working with new versions of WS

The following code used to be enough to connect with the websocket

    client.println("GET / HTTP/1.1");
    client.println("Host: 8080-c99d06fd-7ec6-4c97-9f2a-0e9f888d2ce0.ws-us02.gitpod.io/");
    client.println("Upgrade: websocket");
    client.println("Connection: Upgrade");
    client.println("Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==");
    client.println("Sec-WebSocket-Version: 13");
    client.println();

but more seems to be needed now perhaps even a type of encryption like SHA1. Anyone got any ideas?

Ok. so I am doing better than I thought I would. I got my old version websocket working on Gitpod.
To get any github working on gitpod.io just add gitpod.io/# infront of the github URL. Opens a debian linux box ready to install the github based on a package.json file. Very slick.

My new websocket github is at
GitHub - hpssjellis/arduino-simple-websocket: How to connect an Arduino to a node js websocket for fast webpage to Arduino communication I just needed the Arduino to work with SSL. I also added a few new lines for modern websockets that seemed to work.

String myRandWebSocket = String(rand()*10000+10000); //attempt at random security

client.println("GET / HTTP/1.1");
client.println("Host: "+String(server));
client.println("Upgrade: websocket");
client.println("Connection: Upgrade");
// client.println("Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==");
client.println("Sec-WebSocket-Key: " + String(myRandWebSocket) + String(myRandWebSocket));
client.println("Sec-WebSocket-Protocol: chat, superchat, soap");
client.println("Sec-WebSocket-Version: 13");
client.println("Sec-WebSocket-Extensions: deflate-frame");
client.println("Origin: http://111.111.1.11"); // my Arduino wifi ip.
client.println(); 

So that is good. Next I have to go through and find out what has changed in the last 6 years to the “ws” file that is breaking my code.

The website for "ws" versions is at ws - npm so I guess that is where I go next.

Got it working thanks to one of the maintainers of npm ws ws - npm called Ipinca
https://github.com/lpinca

My github is at https://github.com/hpssjellis/arduino-simple-websocket and allows an Arduino to very fast communicate with a webpage using a node js websocket chat server running on Gitpod.io

If you run this code, with github authentication

https://gitpod.io/#github.com/hpssjellis/arduino-simple-websocket

It auto loads a node js websocket. Click preview. Then load this code on your nano 33 IoT but you need to edit the URL for the websocket without the https::// or the trailing “/”

/*
 * socket.ino
 * 
 * created 13 July 2010
 * by dlf (Metodo2 srl)
 * modified 31 May 2012
 * by Tom Igoe
 * 
 * modified By Jeremy Ellis 
 * twitter @rocksetta
 * Webpage http://rocksetta.com
 * Arduino High School Robotics Course at
 * https://github.com/hpssjellis/arduino-high-school-robotics-course
 * 
 *  Update Feb 12th, 2020
 *  Specifically for the Arduino Nano 33 IoT
 *
 */


#include <SPI.h>
#include <WiFiNINA.h>

#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)


///////////////////////// Node Websocket server url without http:// or ending /         ////////

//   so https://myURL/

//   becomes

//   myURL

char server[] = "8080-e71e03c0-51bc-4fc8-8019-df8863ff0ce8.ws-us02.gitpod.io";    

///////////////////////// above is important  ////////////////////////////////////////////////////

String myRandWebSocket = String(rand()*10000+10000); //attempt at random security


// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
//WiFiClient client;
WiFiSSLClient client;

void setup() {
  pinMode(LED_BUILTIN,OUTPUT);
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to wifi");
  printWifiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:  
  //if (client.connect(server, 80)) {
  if (client.connect(server, 443)) {
    Serial.println("connected to server");
    // Make a HTTP request:
    client.println("GET / HTTP/1.1");
    client.println("Host: "+String(server));
    client.println("Upgrade: websocket");
    client.println("Connection: Upgrade");
    client.println("Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==");
    client.println("Sec-WebSocket-Version: 13");
    client.println();   
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  while (client.available()) {
    char c = client.read();
    Serial.write(c);
    if (c == 'A') {
       digitalWrite(LED_BUILTIN, 1);               // GET /H turns the LED on
       Serial.println();
    }    
    if (c == 'B') {
       digitalWrite(LED_BUILTIN, 0);               // GET /H turns the LED on
       Serial.println();
    }
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting from server.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Then click the buttons “A” or “B” to very fast control the LED on your nano 33 IoT

Enjoy!

Hi Jeremy - I've been looking at your amazing work.. I've recently bought a Particle Photon and was looking to do a write via a websocket from the photon to a nodejs server. Does the write from Photon code still work - like a single byte of 127, 1 and then the payload ?

I was planning to update everything so I could use your latest stuff with a Photon. Although I am just thinking - Nano33.... :slight_smile:

From the old photon code.

IPAddress clientIP = client.remoteIP();
       Particle.publish("Remote IP", String(clientIP), 60, PRIVATE);   
       client.write(byte(129));  // tells websockey using Frames
       client.write(byte(1));    // sending only 1 byte. works up to 125 bytes
       client.write("A");        // sending the one byte. any Ascii code !
       if (myUsbSerialDebugOn){
           Serial.print("A");
       }

Sorry Davy. Just saw this, I have been working on some other stuff. I also was going to use that stuff on the Nano 33 BLE but have now switched to the PortentaH7. Yes in theory all the Photon websocket code still works. I have been using gitpod to run the websocket instead of what I probably used in those examples. Can you supply links to what you were looking at. I have so many redentions not really sure what you are using.

The last main link I used was GitHub - hpssjellis/Particle-Spark-Core-Photon-Websocket-Hack: A tiny demo using the einaros/ws WebSockets implementation. but I now use gitpod instead of reple.it so there may be a few changes.

Good luck. Sorry I move around so fast. Getting lost in my own work.

Jeremy.

I was looking around and this link my be my latest websocket using gitpod. Be good if it is the one that works now