WebSockets are an easy way to exchange data between a client and server, full-duplex, over a single TCP connection. This example uses the ArduinoWebSockets library, which needs only a few modifications to work with the Industruino's D21G platform.
We will run a websocket server on a laptop (e.g. the node.js/simple.js example included in the above library), and our Industruino will connect over Ethernet to this server.
- start the websocket server
- start the Industruino websocket client
- the Industruino connects to the server and send a hello message
- the server sends a hello message to the Industruino client
- whenever an Industruino button is pressed, it sends 'ENTER', 'UP', 'DOWN' to the server
- when the server disconnects (timeout of 1min), the Industruino displays 'disconnected'
- the Industruino client connects again when the 'ENTER' button is pressed
Above is the console output of the simple.js websocket server on a Linux Ubuntu laptop.
The library configuration files need 2 small modifications:
- config.h needs to refer to the W5500 chip because that is the one used in the Industruino Ethernet module
- platform.h needs to explicitely state that we have an SAMD architecture; Industruino does not define ARDUINO_SAMD_ZERO so we have to include after line 18:
#define PLATFORM_ARCH PLATFORM_ARCHITECTURE_SAMD21
The Serial Monitor has a lot of debugging information in case of trouble.
The code for the client is below; you will need to edit the server IP address as applicable. The code retrieves a unique MAC address from the RTC EEPROM included in the D21G topboard, you can of course set the MAC address manually to any other constant.
/* WEBSOCKET DEMO for Industruino using library https://github.com/skaarj1989/ArduinoWebSockets based on simple-client.ino example configure config.h line 24 for W5500 (Ethernet chip used in Industruino Ethernet module) edit platform.h to include a line after line 18: #define PLATFORM_ARCH PLATFORM_ARCHITECTURE_SAMD21 // include for INDUSTRUINO (because ARDUINO_SAMD_ZERO is not defined for Industruino) you need a websocket server, e.g. the one included in the library node.js/simple.js (tested on Linux Ubuntu) working on Industruino D21G + Ethernet > the sketch connects to the server > displays a message from the server > sends a string message to the server > whenever a button is pressed on the Industruino, it sends 'ENTER', 'UP', 'DOWN' to the server > displays 'disconnected' when the server closes the connection > re-connects again to the server when the Enter button is pressed */ #include <WebSocketClient.h> // includes SPI and Ethernet2 WebSocketClient client; #include <Wire.h> // for RTC EEPROM MAC byte mac[6]; // read from RTC EEPROM const char *server = "192.168.1.121"; const int port = 3000; #include <UC1701.h> static UC1701 lcd; unsigned long pressed_timestamp; unsigned long pressed_interval = 200; boolean ws_connected = false; ///////////////////////////////////////////////////////////////////////// void onOpen(WebSocket &ws) { SerialUSB.println("Connected"); lcd.setCursor(0, 6); lcd.print("connected "); ws_connected = true; char message[] = "Hello from your Industruino websocket client!"; ws.send(TEXT, message, strlen(message)); } void onClose(WebSocket &ws, const eWebSocketCloseEvent code, const char *reason, uint16_t length) { SerialUSB.println("Disconnected"); lcd.setCursor(0, 6); lcd.print("disconnected "); ws_connected = false; } void onMessage(WebSocket &ws, const eWebSocketDataType dataType, const char *message, uint16_t length) { switch (dataType) { case TEXT: SerialUSB.print("Received: "); SerialUSB.println(message); lcd.setCursor(0, 6); lcd.print(message); lcd.print(" "); break; case BINARY: SerialUSB.println("Received binary data"); break; } } void onError(const eWebSocketError code) { SerialUSB.print("Error: "); SerialUSB.println(code); lcd.setCursor(0, 6); lcd.print("error: "); lcd.print(code); lcd.print(" "); } ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// void setup() { SerialUSB.begin(115200); SerialUSB.println("Starting sketch: WebSocket DEMO"); Wire.begin(); // for MAC from RTC EEPROM pinMode(26, OUTPUT); digitalWrite(26, HIGH); // LCD full backlight lcd.begin(); lcd.setCursor(0, 0); lcd.print("WebSocket DEMO"); SerialUSB.println("Get unique MAC from RTC EEPROM"); readMACfromRTC(); // MAC stored in RTC EEPROM if (Ethernet.begin(mac) == 0) { SerialUSB.println("failed to start Ethernet with DCHP, stop here"); while (true) ; } SerialUSB.print("Client IP: "); SerialUSB.println(Ethernet.localIP()); lcd.setCursor(0, 2); lcd.print("IP: "); lcd.print(Ethernet.localIP()); lcd.setCursor(0, 3); lcd.print("server:"); lcd.setCursor(0, 4); lcd.print(server); lcd.print(":"); lcd.print(port); SerialUSB.print("Trying to connect to server: "); SerialUSB.print(server); SerialUSB.print(":"); SerialUSB.println(port); client.setOnOpenCallback(onOpen); client.setOnCloseCallback(onClose); client.setOnMessageCallback(onMessage); if (!client.open(server, port)) { SerialUSB.println("Connection failed, stop here"); lcd.setCursor(0, 6); lcd.print("connection failed"); while (true) ; } SerialUSB.println("Connected"); } ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// void loop() { client.listen(); if (SerialUSB.available()) { char msg[1]; msg[0] = SerialUSB.read(); client.send(TEXT, msg, 1); } if (!digitalRead(24) && millis() - pressed_timestamp > pressed_interval) { char msg[] = "ENTER"; client.send(TEXT, msg, strlen(msg)); pressed_timestamp = millis(); if (!ws_connected) { if (!client.open(server, port)) { SerialUSB.println("Connection failed, stop here"); lcd.setCursor(0, 6); lcd.print("connection failed"); while (true) ; } } } if (!digitalRead(23) && millis() - pressed_timestamp > pressed_interval) { char msg[] = "DOWN"; client.send(TEXT, msg, strlen(msg)); pressed_timestamp = millis(); } if (!digitalRead(25) && millis() - pressed_timestamp > pressed_interval) { char msg[] = "UP"; client.send(TEXT, msg, strlen(msg)); pressed_timestamp = millis(); } } ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // the RTC has a MAC address stored in EEPROM - 8 bytes 0xf0 to 0xf7 void readMACfromRTC() { SerialUSB.println("READING MAC from RTC EEPROM"); int mac_index = 0; for (int i = 0; i < 8; i++) { // read 8 bytes of 64-bit MAC address, 3 bytes valid OUI, 5 bytes unique EI byte m = readByte(0x57, 0xf0 + i); SerialUSB.print(m, HEX); if (i < 7) SerialUSB.print(":"); if (i != 3 && i != 4) { // for 6-bytes MAC, skip first 2 bytes of EI mac[mac_index] = m; mac_index++; } } SerialUSB.println(); SerialUSB.print("Extracted 6-byte MAC address: "); for (int u = 0; u < 6; u++) { SerialUSB.print(mac[u], HEX); if (u < 5) SerialUSB.print(":"); } SerialUSB.println(); } ///////////////////////////////////////////////////////////////////////// // the RTC has a MAC address stored in EEPROM uint8_t readByte(uint8_t i2cAddr, uint8_t dataAddr) { Wire.beginTransmission(i2cAddr); Wire.write(dataAddr); Wire.endTransmission(false); // don't send stop Wire.requestFrom(i2cAddr, 1); return Wire.read(); }