Hardened (dis)connections

Added support fot multiple sessions (Currently 5 max. Each connection
costs RAM!)
Each session can send data to the gateway. Data from the gateway will be
broadcasted to all connected clients.
Added serial logging of client (dis)connections. Inspect serial terminal
in case of problems.
This commit is contained in:
Yveaux
2015-09-04 19:54:45 +02:00
parent b997861f59
commit f03f4f9412
2 changed files with 100 additions and 56 deletions
@@ -124,23 +124,33 @@ MySensor gw(transport, hw
#define IP_PORT 5003 // The port you want to open #define IP_PORT 5003 // The port you want to open
#define MAX_SRV_CLIENTS 5 // how many clients should be able to telnet to this ESP8266
// a R/W server on the port // a R/W server on the port
WiFiServer server(IP_PORT); static WiFiServer server(IP_PORT);
// handle to open connection static WiFiClient clients[MAX_SRV_CLIENTS];
WiFiClient client; static bool clientsConnected[MAX_SRV_CLIENTS];
static inputBuffer inputString[MAX_SRV_CLIENTS];
char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
int inputPos = 0;
bool sentReady = false;
void output(const char *fmt, ... ) {
void output(const char *fmt, ... )
{
char serialBuffer[MAX_SEND_LENGTH];
va_list args; va_list args;
va_start (args, fmt ); va_start (args, fmt );
vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args); vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args);
va_end (args); va_end (args);
Serial.print(serialBuffer); Serial.print(serialBuffer);
server.write(serialBuffer); for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
{
if (clients[i] && clients[i].connected())
{
// Serial.print("Client "); Serial.print(i); Serial.println(" write");
clients[i].write((uint8_t*)serialBuffer, strlen(serialBuffer));
}
}
} }
void setup() void setup()
@@ -153,7 +163,8 @@ void setup()
Serial.print("Connecting to "); Serial.println(ssid); Serial.print("Connecting to "); Serial.println(ssid);
(void)WiFi.begin(ssid, pass); (void)WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) { while (WiFi.status() != WL_CONNECTED)
{
delay(500); delay(500);
Serial.print("."); Serial.print(".");
} }
@@ -168,6 +179,7 @@ void setup()
// start listening for clients // start listening for clients
server.begin(); server.begin();
server.setNoDelay(true);
} }
@@ -177,46 +189,73 @@ void loop() {
checkButtonTriggeredInclusion(); checkButtonTriggeredInclusion();
checkInclusionFinished(); checkInclusionFinished();
// Go over list of clients and stop any that are no longer connected.
// If the server has a new client connection it will be assigned to a free slot.
bool allSlotsOccupied = true;
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
{
if (!clients[i].connected())
{
if (clientsConnected[i])
{
Serial.print("Client "); Serial.print(i); Serial.println(" disconnected");
clients[i].stop();
}
//check if there are any new clients //check if there are any new clients
if (server.hasClient()) if (server.hasClient())
{ {
if (client) clients[i] = server.available();
{ inputString[i].idx = 0;
client.stop(); Serial.print("Client "); Serial.print(i); Serial.println(" connected");
}
client = server.available();
output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY);
} }
}
bool connected = clients[i].connected();
clientsConnected[i] = connected;
allSlotsOccupied &= connected;
}
if (allSlotsOccupied && server.hasClient())
{
//no free/disconnected spot so reject
Serial.println("No free slot available");
WiFiClient c = server.available();
c.stop();
}
if (client) { // Loop over clients connect and read available data
if (!client.connected()) { for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
client.stop(); {
} else if (client.available()) { while(clients[i].connected() && clients[i].available())
// read the bytes incoming from the client {
char inChar = client.read(); char inChar = clients[i].read();
if (inputPos<MAX_RECEIVE_LENGTH-1) { if ( inputString[i].idx < MAX_RECEIVE_LENGTH - 1 )
{
// if newline then command is complete // if newline then command is complete
if (inChar == '\n') { if (inChar == '\n')
Serial.println("Finished"); {
// a command was issued by the client // a command was issued by the client
// we will now try to send it to the actuator // we will now try to send it to the actuator
inputString[inputPos] = 0; inputString[i].string[inputString[i].idx] = 0;
// echo the string to the serial port // echo the string to the serial port
Serial.print(inputString); Serial.print("Client "); Serial.print(i); Serial.print(": "); Serial.println(inputString[i].string);
parseAndSend(gw, inputString); parseAndSend(gw, inputString[i].string);
// clear the string: // clear the string:
inputPos = 0; inputString[i].idx = 0;
// Finished with this client's message. Next loop() we'll see if there's more to read.
break;
} else { } else {
// add it to the inputString: // add it to the inputString:
inputString[inputPos] = inChar; inputString[i].string[inputString[i].idx++] = inChar;
inputPos++;
} }
} else { } else {
// Incoming message too long. Throw away // Incoming message too long. Throw away
inputPos = 0; Serial.print("Client "); Serial.print(i); Serial.println(": Message too long");
inputString[i].idx = 0;
// Finished with this client's message. Next loop() we'll see if there's more to read.
break;
} }
} }
} }
@@ -3,13 +3,19 @@
#ifdef ARDUINO #ifdef ARDUINO
static uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled static uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled
static uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode static uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode
#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller #define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller
#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller #define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller
typedef struct
{
char string[MAX_RECEIVE_LENGTH];
uint8_t idx;
} inputBuffer;
static volatile boolean buttonTriggeredInclusion; static volatile boolean buttonTriggeredInclusion;
static boolean inclusionMode; // Keeps track on inclusion mode static boolean inclusionMode; // Keeps track on inclusion mode
bool inclusionButtonSupported = false; bool inclusionButtonSupported = false;
@@ -20,7 +26,6 @@ MyParserSerial parser;
void setInclusionMode(boolean newMode); void setInclusionMode(boolean newMode);
char convBuf[MAX_PAYLOAD*2+1]; char convBuf[MAX_PAYLOAD*2+1];
char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera
unsigned long inclusionStartTime; unsigned long inclusionStartTime;