mirror of
https://github.com/arduino-libraries/ArduinoHttpClient.git
synced 2025-04-19 21:22:15 +03:00
Merge pull request #5 from sandeepmistry/websocket
Add initial WebSocket client
This commit is contained in:
commit
a19197cebe
@ -6,5 +6,6 @@
|
|||||||
#define ArduinoHttpClient_h
|
#define ArduinoHttpClient_h
|
||||||
|
|
||||||
#include "HttpClient.h"
|
#include "HttpClient.h"
|
||||||
|
#include "WebSocketClient.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -439,7 +439,7 @@ int HttpClient::responseStatusCode()
|
|||||||
delay(kHttpWaitForDataDelay);
|
delay(kHttpWaitForDataDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( (c == '\n') && (iStatusCode < 200) )
|
if ( (c == '\n') && (iStatusCode < 200 && iStatusCode != 101) )
|
||||||
{
|
{
|
||||||
// We've reached the end of an informational status line
|
// We've reached the end of an informational status line
|
||||||
c = '\0'; // Clear c so we'll go back into the data reading loop
|
c = '\0'; // Clear c so we'll go back into the data reading loop
|
||||||
@ -447,7 +447,7 @@ int HttpClient::responseStatusCode()
|
|||||||
}
|
}
|
||||||
// If we've read a status code successfully but it's informational (1xx)
|
// If we've read a status code successfully but it's informational (1xx)
|
||||||
// loop back to the start
|
// loop back to the start
|
||||||
while ( (iState == eStatusCodeRead) && (iStatusCode < 200) );
|
while ( (iState == eStatusCodeRead) && (iStatusCode < 200 && iStatusCode != 101) );
|
||||||
|
|
||||||
if ( (c == '\n') && (iState == eStatusCodeRead) )
|
if ( (c == '\n') && (iState == eStatusCodeRead) )
|
||||||
{
|
{
|
||||||
|
371
WebSocketClient.cpp
Normal file
371
WebSocketClient.cpp
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
// (c) Copyright Arduino. 2016
|
||||||
|
// Released under Apache License, version 2.0
|
||||||
|
|
||||||
|
#include "b64.h"
|
||||||
|
|
||||||
|
#include "WebSocketClient.h"
|
||||||
|
|
||||||
|
WebSocketClient::WebSocketClient(Client& aClient, const char* aServerName, uint16_t aServerPort)
|
||||||
|
: HttpClient(aClient, aServerName, aServerPort),
|
||||||
|
iTxStarted(false),
|
||||||
|
iRxSize(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WebSocketClient::WebSocketClient(Client& aClient, const String& aServerName, uint16_t aServerPort)
|
||||||
|
: HttpClient(aClient, aServerName, aServerPort),
|
||||||
|
iTxStarted(false),
|
||||||
|
iRxSize(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WebSocketClient::WebSocketClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort)
|
||||||
|
: HttpClient(aClient, aServerAddress, aServerPort),
|
||||||
|
iTxStarted(false),
|
||||||
|
iRxSize(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::begin(const char* aPath)
|
||||||
|
{
|
||||||
|
// start the GET request
|
||||||
|
beginRequest();
|
||||||
|
connectionKeepAlive();
|
||||||
|
int status = get(aPath);
|
||||||
|
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
uint8_t randomKey[13];
|
||||||
|
char base64RandomKey[21];
|
||||||
|
|
||||||
|
// create a random key for the connection upgrade
|
||||||
|
for (int i = 0; i < (int)sizeof(randomKey); i++)
|
||||||
|
{
|
||||||
|
randomKey[i] = random(0x01, 0xff);
|
||||||
|
}
|
||||||
|
memset(base64RandomKey, 0x00, sizeof(base64RandomKey));
|
||||||
|
b64_encode(randomKey, sizeof(randomKey), (unsigned char*)base64RandomKey, sizeof(base64RandomKey));
|
||||||
|
|
||||||
|
// start the connection upgrade sequence
|
||||||
|
sendHeader("Upgrade", "websocket");
|
||||||
|
sendHeader("Connection", "Upgrade");
|
||||||
|
sendHeader("Sec-WebSocket-Key", base64RandomKey);
|
||||||
|
sendHeader("Sec-WebSocket-Version", "13");
|
||||||
|
endRequest();
|
||||||
|
|
||||||
|
status = responseStatusCode();
|
||||||
|
|
||||||
|
if (status > 0)
|
||||||
|
{
|
||||||
|
skipResponseHeaders();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iRxSize = 0;
|
||||||
|
|
||||||
|
// status code of 101 means success
|
||||||
|
return (status == 101) ? 0 : status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::begin(const String& aPath)
|
||||||
|
{
|
||||||
|
return begin(aPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::beginMessage(int aType)
|
||||||
|
{
|
||||||
|
if (iTxStarted)
|
||||||
|
{
|
||||||
|
// fail TX already started
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iTxStarted = true;
|
||||||
|
iTxMessageType = (aType & 0xf);
|
||||||
|
iTxSize = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::endMessage()
|
||||||
|
{
|
||||||
|
if (!iTxStarted)
|
||||||
|
{
|
||||||
|
// fail TX not started
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send FIN + the message type (opcode)
|
||||||
|
HttpClient::write(0x80 | iTxMessageType);
|
||||||
|
|
||||||
|
// the message is masked (0x80)
|
||||||
|
// send the length
|
||||||
|
if (iTxSize < 126)
|
||||||
|
{
|
||||||
|
HttpClient::write(0x80 | (uint8_t)iTxSize);
|
||||||
|
}
|
||||||
|
else if (iTxSize < 0xffff)
|
||||||
|
{
|
||||||
|
HttpClient::write(0x80 | 126);
|
||||||
|
HttpClient::write((iTxSize >> 8) & 0xff);
|
||||||
|
HttpClient::write((iTxSize >> 0) & 0xff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpClient::write(0x80 | 127);
|
||||||
|
HttpClient::write((iTxSize >> 56) & 0xff);
|
||||||
|
HttpClient::write((iTxSize >> 48) & 0xff);
|
||||||
|
HttpClient::write((iTxSize >> 40) & 0xff);
|
||||||
|
HttpClient::write((iTxSize >> 32) & 0xff);
|
||||||
|
HttpClient::write((iTxSize >> 24) & 0xff);
|
||||||
|
HttpClient::write((iTxSize >> 16) & 0xff);
|
||||||
|
HttpClient::write((iTxSize >> 8) & 0xff);
|
||||||
|
HttpClient::write((iTxSize >> 0) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t maskKey[4];
|
||||||
|
|
||||||
|
// create a random mask for the data and send
|
||||||
|
for (int i = 0; i < (int)sizeof(maskKey); i++)
|
||||||
|
{
|
||||||
|
maskKey[i] = random(0xff);
|
||||||
|
}
|
||||||
|
HttpClient::write(maskKey, sizeof(maskKey));
|
||||||
|
|
||||||
|
// mask the data and send
|
||||||
|
for (int i = 0; i < (int)iTxSize; i++) {
|
||||||
|
iTxBuffer[i] ^= maskKey[i % sizeof(maskKey)];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t txSize = iTxSize;
|
||||||
|
|
||||||
|
iTxStarted = false;
|
||||||
|
iTxSize = 0;
|
||||||
|
|
||||||
|
return (HttpClient::write(iTxBuffer, txSize) == txSize) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WebSocketClient::write(uint8_t aByte)
|
||||||
|
{
|
||||||
|
return write(&aByte, sizeof(aByte));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WebSocketClient::write(const uint8_t *aBuffer, size_t aSize)
|
||||||
|
{
|
||||||
|
if (iState < eReadingBody)
|
||||||
|
{
|
||||||
|
// have not upgraded the connection yet
|
||||||
|
return HttpClient::write(aBuffer, aSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iTxStarted)
|
||||||
|
{
|
||||||
|
// fail TX not started
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the write size, fits in the buffer
|
||||||
|
if ((iTxSize + aSize) > sizeof(iTxBuffer))
|
||||||
|
{
|
||||||
|
aSize = sizeof(iTxSize) - iTxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy data into the buffer
|
||||||
|
memcpy(iTxBuffer + iTxSize, aBuffer, aSize);
|
||||||
|
|
||||||
|
iTxSize += aSize;
|
||||||
|
|
||||||
|
return aSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::parseMessage()
|
||||||
|
{
|
||||||
|
flushRx();
|
||||||
|
|
||||||
|
// make sure 2 bytes (opcode + length)
|
||||||
|
// are available
|
||||||
|
if (HttpClient::available() < 2)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read open code and length
|
||||||
|
uint8_t opcode = HttpClient::read();
|
||||||
|
int length = HttpClient::read();
|
||||||
|
|
||||||
|
if ((opcode & 0x0f) == 0)
|
||||||
|
{
|
||||||
|
// continuation, use previous opcode and update flags
|
||||||
|
iRxOpCode |= opcode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iRxOpCode = opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
iRxMasked = (length & 0x80);
|
||||||
|
length &= 0x7f;
|
||||||
|
|
||||||
|
// read the RX size
|
||||||
|
if (length < 126)
|
||||||
|
{
|
||||||
|
iRxSize = length;
|
||||||
|
}
|
||||||
|
else if (length == 126)
|
||||||
|
{
|
||||||
|
iRxSize = (HttpClient::read() << 8) | HttpClient::read();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iRxSize = ((uint64_t)HttpClient::read() << 56) |
|
||||||
|
((uint64_t)HttpClient::read() << 48) |
|
||||||
|
((uint64_t)HttpClient::read() << 40) |
|
||||||
|
((uint64_t)HttpClient::read() << 32) |
|
||||||
|
((uint64_t)HttpClient::read() << 24) |
|
||||||
|
((uint64_t)HttpClient::read() << 16) |
|
||||||
|
((uint64_t)HttpClient::read() << 8) |
|
||||||
|
(uint64_t)HttpClient::read();
|
||||||
|
}
|
||||||
|
|
||||||
|
// read in the mask, if present
|
||||||
|
if (iRxMasked)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)sizeof(iRxMaskKey); i++)
|
||||||
|
{
|
||||||
|
iRxMaskKey[i] = HttpClient::read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iRxMaskIndex = 0;
|
||||||
|
|
||||||
|
if (TYPE_CONNECTION_CLOSE == messageType())
|
||||||
|
{
|
||||||
|
flushRx();
|
||||||
|
stop();
|
||||||
|
iRxSize = 0;
|
||||||
|
}
|
||||||
|
else if (TYPE_PING == messageType())
|
||||||
|
{
|
||||||
|
beginMessage(TYPE_PONG);
|
||||||
|
while(available())
|
||||||
|
{
|
||||||
|
write(read());
|
||||||
|
}
|
||||||
|
endMessage();
|
||||||
|
|
||||||
|
iRxSize = 0;
|
||||||
|
}
|
||||||
|
else if (TYPE_PONG == messageType())
|
||||||
|
{
|
||||||
|
flushRx();
|
||||||
|
iRxSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return iRxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::messageType()
|
||||||
|
{
|
||||||
|
return (iRxOpCode & 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebSocketClient::isFinal()
|
||||||
|
{
|
||||||
|
return ((iRxOpCode & 0x80) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
String WebSocketClient::readString()
|
||||||
|
{
|
||||||
|
int avail = available();
|
||||||
|
String s;
|
||||||
|
|
||||||
|
if (avail > 0)
|
||||||
|
{
|
||||||
|
s.reserve(avail);
|
||||||
|
|
||||||
|
for (int i = 0; i < avail; i++)
|
||||||
|
{
|
||||||
|
s += (char)read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::ping()
|
||||||
|
{
|
||||||
|
uint8_t pingData[16];
|
||||||
|
|
||||||
|
// create random data for the ping
|
||||||
|
for (int i = 0; i < (int)sizeof(pingData); i++)
|
||||||
|
{
|
||||||
|
pingData[i] = random(0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
beginMessage(TYPE_PING);
|
||||||
|
write(pingData, sizeof(pingData));
|
||||||
|
return endMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::available()
|
||||||
|
{
|
||||||
|
if (iState < eReadingBody)
|
||||||
|
{
|
||||||
|
return HttpClient::available();
|
||||||
|
}
|
||||||
|
|
||||||
|
return iRxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::read()
|
||||||
|
{
|
||||||
|
byte b;
|
||||||
|
|
||||||
|
if (read(&b, sizeof(b)))
|
||||||
|
{
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::read(uint8_t *aBuffer, size_t aSize)
|
||||||
|
{
|
||||||
|
int readCount = HttpClient::read(aBuffer, aSize);
|
||||||
|
|
||||||
|
if (readCount > 0)
|
||||||
|
{
|
||||||
|
iRxSize -= readCount;
|
||||||
|
|
||||||
|
// unmask the RX data if needed
|
||||||
|
if (iRxMasked)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)aSize; i++, iRxMaskIndex++) {
|
||||||
|
aBuffer[i] ^= iRxMaskKey[iRxMaskIndex % sizeof(iRxMaskKey)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return readCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebSocketClient::peek()
|
||||||
|
{
|
||||||
|
int p = HttpClient::peek();
|
||||||
|
|
||||||
|
if (p != -1 && iRxMasked)
|
||||||
|
{
|
||||||
|
// unmask the RX data if needed
|
||||||
|
p = (uint8_t)p ^ iRxMaskKey[iRxMaskIndex % sizeof(iRxMaskKey)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketClient::flushRx()
|
||||||
|
{
|
||||||
|
while(available())
|
||||||
|
{
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
}
|
99
WebSocketClient.h
Normal file
99
WebSocketClient.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// (c) Copyright Arduino. 2016
|
||||||
|
// Released under Apache License, version 2.0
|
||||||
|
|
||||||
|
#ifndef WebSocketClient_h
|
||||||
|
#define WebSocketClient_h
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "HttpClient.h"
|
||||||
|
|
||||||
|
static const int TYPE_CONTINUATION = 0x0;
|
||||||
|
static const int TYPE_TEXT = 0x1;
|
||||||
|
static const int TYPE_BINARY = 0x2;
|
||||||
|
static const int TYPE_CONNECTION_CLOSE = 0x8;
|
||||||
|
static const int TYPE_PING = 0x9;
|
||||||
|
static const int TYPE_PONG = 0xa;
|
||||||
|
|
||||||
|
class WebSocketClient : public HttpClient
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WebSocketClient(Client& aClient, const char* aServerName, uint16_t aServerPort = HttpClient::kHttpPort);
|
||||||
|
WebSocketClient(Client& aClient, const String& aServerName, uint16_t aServerPort = HttpClient::kHttpPort);
|
||||||
|
WebSocketClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort = HttpClient::kHttpPort);
|
||||||
|
|
||||||
|
/** Start the Web Socket connection to the specified path
|
||||||
|
@param aURLPath Path to use in request (optional, "/" is used by default)
|
||||||
|
@return 0 if successful, else error
|
||||||
|
*/
|
||||||
|
int begin(const char* aPath = "/");
|
||||||
|
int begin(const String& aPath);
|
||||||
|
|
||||||
|
/** Begin to send a message of type (TYPE_TEXT or TYPE_BINARY)
|
||||||
|
Use the write or Stream API's to set message content, followed by endMessage
|
||||||
|
to complete the message.
|
||||||
|
@param aURLPath Path to use in request
|
||||||
|
@return 0 if successful, else error
|
||||||
|
*/
|
||||||
|
int beginMessage(int aType);
|
||||||
|
|
||||||
|
/** Completes sending of a message started by beginMessage
|
||||||
|
@return 0 if successful, else error
|
||||||
|
*/
|
||||||
|
int endMessage();
|
||||||
|
|
||||||
|
/** Try to parse an incoming messages
|
||||||
|
@return 0 if no message available, else size of parsed message
|
||||||
|
*/
|
||||||
|
int parseMessage();
|
||||||
|
|
||||||
|
/** Returns type of current parsed message
|
||||||
|
@return type of current parsedMessage (TYPE_TEXT or TYPE_BINARY)
|
||||||
|
*/
|
||||||
|
int messageType();
|
||||||
|
|
||||||
|
/** Returns if the current message is the final chunk of a split
|
||||||
|
message
|
||||||
|
@return true for final message, false otherwise
|
||||||
|
*/
|
||||||
|
bool isFinal();
|
||||||
|
|
||||||
|
/** Read the current messages as a string
|
||||||
|
@return current message as a string
|
||||||
|
*/
|
||||||
|
String readString();
|
||||||
|
|
||||||
|
/** Send a ping
|
||||||
|
@return 0 if successful, else error
|
||||||
|
*/
|
||||||
|
int ping();
|
||||||
|
|
||||||
|
// Inherited from Print
|
||||||
|
virtual size_t write(uint8_t aByte);
|
||||||
|
virtual size_t write(const uint8_t *aBuffer, size_t aSize);
|
||||||
|
// Inherited from Stream
|
||||||
|
virtual int available();
|
||||||
|
/** Read the next byte from the server.
|
||||||
|
@return Byte read or -1 if there are no bytes available.
|
||||||
|
*/
|
||||||
|
virtual int read();
|
||||||
|
virtual int read(uint8_t *buf, size_t size);
|
||||||
|
virtual int peek();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void flushRx();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool iTxStarted;
|
||||||
|
uint8_t iTxMessageType;
|
||||||
|
uint8_t iTxBuffer[128];
|
||||||
|
uint64_t iTxSize;
|
||||||
|
|
||||||
|
uint8_t iRxOpCode;
|
||||||
|
uint64_t iRxSize;
|
||||||
|
bool iRxMasked;
|
||||||
|
int iRxMaskIndex;
|
||||||
|
uint8_t iRxMaskKey[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
80
examples/SimpleWebSocket/SimpleWebSocket.ino
Normal file
80
examples/SimpleWebSocket/SimpleWebSocket.ino
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
Simple WebSocket client for ArduinoHttpClient library
|
||||||
|
Connects to the WebSocket server, and sends a hello
|
||||||
|
message every 5 seconds
|
||||||
|
|
||||||
|
note: WiFi SSID and password are stored in config.h file.
|
||||||
|
If it is not present, add a new tab, call it "config.h"
|
||||||
|
and add the following variables:
|
||||||
|
char ssid[] = "ssid"; // your network SSID (name)
|
||||||
|
char pass[] = "password"; // your network password
|
||||||
|
|
||||||
|
created 28 Jun 2016
|
||||||
|
by Sandeep Mistry
|
||||||
|
|
||||||
|
this example is in the public domain
|
||||||
|
*/
|
||||||
|
#include <ArduinoHttpClient.h>
|
||||||
|
#include <WiFi101.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
char serverAddress[] = "echo.websocket.org"; // server address
|
||||||
|
int port = 80;
|
||||||
|
|
||||||
|
WiFiClient wifi;
|
||||||
|
WebSocketClient client = WebSocketClient(wifi, serverAddress, port);
|
||||||
|
int status = WL_IDLE_STATUS;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
while ( status != WL_CONNECTED) {
|
||||||
|
Serial.print("Attempting to connect to Network named: ");
|
||||||
|
Serial.println(ssid); // print the network name (SSID);
|
||||||
|
|
||||||
|
// Connect to WPA/WPA2 network:
|
||||||
|
status = WiFi.begin(ssid, pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the SSID of the network you're attached to:
|
||||||
|
Serial.print("SSID: ");
|
||||||
|
Serial.println(WiFi.SSID());
|
||||||
|
|
||||||
|
// print your WiFi shield's IP address:
|
||||||
|
IPAddress ip = WiFi.localIP();
|
||||||
|
Serial.print("IP Address: ");
|
||||||
|
Serial.println(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Serial.println("starting WebSocket client");
|
||||||
|
client.begin();
|
||||||
|
|
||||||
|
while (client.connected()) {
|
||||||
|
Serial.print("Sending hello ");
|
||||||
|
Serial.println(count);
|
||||||
|
|
||||||
|
// send a hello #
|
||||||
|
client.beginMessage(TYPE_TEXT);
|
||||||
|
client.print("hello ");
|
||||||
|
client.print(count);
|
||||||
|
client.endMessage();
|
||||||
|
|
||||||
|
// increment count for next message
|
||||||
|
count++;
|
||||||
|
|
||||||
|
// check if a message is available to be received
|
||||||
|
int messageSize = client.parseMessage();
|
||||||
|
|
||||||
|
if (messageSize > 0) {
|
||||||
|
Serial.println("Received a message:");
|
||||||
|
Serial.println(client.readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait 5 seconds
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("disconnected");
|
||||||
|
}
|
||||||
|
|
@ -1,2 +1,3 @@
|
|||||||
char ssid[] = "ssid"; // your network SSID (name)
|
char ssid[] = "ssid"; // your network SSID (name)
|
||||||
char pass[] = "password"; // your network password
|
char pass[] = "password"; // your network password
|
||||||
|
|
@ -10,6 +10,7 @@
|
|||||||
var express = require('express'); // include express.js
|
var express = require('express'); // include express.js
|
||||||
var app = express(); // a local instance of it
|
var app = express(); // a local instance of it
|
||||||
var bodyParser = require('body-parser'); // include body-parser
|
var bodyParser = require('body-parser'); // include body-parser
|
||||||
|
var WebSocketServer = require('ws').Server // include Web Socket server
|
||||||
|
|
||||||
// you need a body parser:
|
// you need a body parser:
|
||||||
app.use(bodyParser.urlencoded({extended: false})); // for application/x-www-form-urlencoded
|
app.use(bodyParser.urlencoded({extended: false})); // for application/x-www-form-urlencoded
|
||||||
@ -40,3 +41,17 @@ app.all('/*', function (request, response) {
|
|||||||
|
|
||||||
// start the server:
|
// start the server:
|
||||||
var server = app.listen(8080, serverStart);
|
var server = app.listen(8080, serverStart);
|
||||||
|
|
||||||
|
// create a WebSocket server and attach it to the server
|
||||||
|
var wss = new WebSocketServer({server: server});
|
||||||
|
|
||||||
|
wss.on('connection', function connection(ws) {
|
||||||
|
// new connection, add message listener
|
||||||
|
ws.on('message', function incoming(message) {
|
||||||
|
// received a message
|
||||||
|
console.log('received: %s', message);
|
||||||
|
|
||||||
|
// echo it back
|
||||||
|
ws.send(message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
"name": "node_test_server",
|
"name": "node_test_server",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"author": {
|
"author": {
|
||||||
"name":"Tom Igoe"
|
"name": "Tom Igoe"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"body-parser": ">=1.11.0",
|
||||||
"express": ">=4.0.0",
|
"express": ">=4.0.0",
|
||||||
"body-parser" : ">=1.11.0",
|
"multer": "*",
|
||||||
"multer" : "*"
|
"ws": "^1.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "0.10.x",
|
"node": "0.10.x",
|
||||||
|
15
keywords.txt
15
keywords.txt
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
ArduinoHttpClient KEYWORD1
|
ArduinoHttpClient KEYWORD1
|
||||||
HttpClient KEYWORD1
|
HttpClient KEYWORD1
|
||||||
|
WebSocketClient KEYWORD1
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
@ -35,6 +36,14 @@ readHeaderName KEYWORD2
|
|||||||
readHeaderValue KEYWORD2
|
readHeaderValue KEYWORD2
|
||||||
responseBody KEYWORD2
|
responseBody KEYWORD2
|
||||||
|
|
||||||
|
beginMessage KEYWORD2
|
||||||
|
endMessage KEYWORD2
|
||||||
|
parseMessage KEYWORD2
|
||||||
|
messageType KEYWORD2
|
||||||
|
isFinal KEYWORD2
|
||||||
|
readString KEYWORD2
|
||||||
|
ping KEYWORD2
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Constants (LITERAL1)
|
# Constants (LITERAL1)
|
||||||
#######################################
|
#######################################
|
||||||
@ -44,3 +53,9 @@ HTTP_ERROR_API LITERAL1
|
|||||||
HTTP_ERROR_TIMED_OUT LITERAL1
|
HTTP_ERROR_TIMED_OUT LITERAL1
|
||||||
HTTP_ERROR_INVALID_RESPONSE LITERAL1
|
HTTP_ERROR_INVALID_RESPONSE LITERAL1
|
||||||
|
|
||||||
|
TYPE_CONTINUATION LITERAL1
|
||||||
|
TYPE_TEXT LITERAL1
|
||||||
|
TYPE_BINARY LITERAL1
|
||||||
|
TYPE_CONNECTION_CLOSE LITERAL1
|
||||||
|
TYPE_PING LITERAL1
|
||||||
|
TYPE_PONG LITERAL1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user