Skip to content

Commit f03f4f9

Browse files
author
Yveaux
committed
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.
1 parent b997861 commit f03f4f9

File tree

2 files changed

+100
-56
lines changed

2 files changed

+100
-56
lines changed

libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino

Lines changed: 93 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -123,24 +123,34 @@ MySensor gw(transport, hw
123123
);
124124

125125

126-
#define IP_PORT 5003 // The port you want to open
126+
#define IP_PORT 5003 // The port you want to open
127+
#define MAX_SRV_CLIENTS 5 // how many clients should be able to telnet to this ESP8266
127128

128129
// a R/W server on the port
129-
WiFiServer server(IP_PORT);
130-
// handle to open connection
131-
WiFiClient client;
132-
133-
char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface
134-
int inputPos = 0;
135-
bool sentReady = false;
136-
137-
void output(const char *fmt, ... ) {
138-
va_list args;
139-
va_start (args, fmt );
140-
vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args);
141-
va_end (args);
142-
Serial.print(serialBuffer);
143-
server.write(serialBuffer);
130+
static WiFiServer server(IP_PORT);
131+
static WiFiClient clients[MAX_SRV_CLIENTS];
132+
static bool clientsConnected[MAX_SRV_CLIENTS];
133+
static inputBuffer inputString[MAX_SRV_CLIENTS];
134+
135+
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
136+
137+
138+
void output(const char *fmt, ... )
139+
{
140+
char serialBuffer[MAX_SEND_LENGTH];
141+
va_list args;
142+
va_start (args, fmt );
143+
vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args);
144+
va_end (args);
145+
Serial.print(serialBuffer);
146+
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
147+
{
148+
if (clients[i] && clients[i].connected())
149+
{
150+
// Serial.print("Client "); Serial.print(i); Serial.println(" write");
151+
clients[i].write((uint8_t*)serialBuffer, strlen(serialBuffer));
152+
}
153+
}
144154
}
145155

146156
void setup()
@@ -153,7 +163,8 @@ void setup()
153163
Serial.print("Connecting to "); Serial.println(ssid);
154164

155165
(void)WiFi.begin(ssid, pass);
156-
while (WiFi.status() != WL_CONNECTED) {
166+
while (WiFi.status() != WL_CONNECTED)
167+
{
157168
delay(500);
158169
Serial.print(".");
159170
}
@@ -168,6 +179,7 @@ void setup()
168179

169180
// start listening for clients
170181
server.begin();
182+
server.setNoDelay(true);
171183
}
172184

173185

@@ -176,47 +188,74 @@ void loop() {
176188

177189
checkButtonTriggeredInclusion();
178190
checkInclusionFinished();
179-
180-
//check if there are any new clients
181-
if (server.hasClient())
191+
192+
// Go over list of clients and stop any that are no longer connected.
193+
// If the server has a new client connection it will be assigned to a free slot.
194+
bool allSlotsOccupied = true;
195+
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
182196
{
183-
if (client)
197+
if (!clients[i].connected())
184198
{
185-
client.stop();
199+
if (clientsConnected[i])
200+
{
201+
Serial.print("Client "); Serial.print(i); Serial.println(" disconnected");
202+
clients[i].stop();
203+
}
204+
//check if there are any new clients
205+
if (server.hasClient())
206+
{
207+
clients[i] = server.available();
208+
inputString[i].idx = 0;
209+
Serial.print("Client "); Serial.print(i); Serial.println(" connected");
210+
output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY);
211+
}
186212
}
187-
client = server.available();
188-
output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY);
189-
}
190-
191-
if (client) {
192-
if (!client.connected()) {
193-
client.stop();
194-
} else if (client.available()) {
195-
// read the bytes incoming from the client
196-
char inChar = client.read();
197-
if (inputPos<MAX_RECEIVE_LENGTH-1) {
198-
// if newline then command is complete
199-
if (inChar == '\n') {
200-
Serial.println("Finished");
201-
// a command was issued by the client
202-
// we will now try to send it to the actuator
203-
inputString[inputPos] = 0;
204-
205-
// echo the string to the serial port
206-
Serial.print(inputString);
207-
208-
parseAndSend(gw, inputString);
209-
210-
// clear the string:
211-
inputPos = 0;
212-
} else {
213-
// add it to the inputString:
214-
inputString[inputPos] = inChar;
215-
inputPos++;
216-
}
213+
bool connected = clients[i].connected();
214+
clientsConnected[i] = connected;
215+
allSlotsOccupied &= connected;
216+
}
217+
if (allSlotsOccupied && server.hasClient())
218+
{
219+
//no free/disconnected spot so reject
220+
Serial.println("No free slot available");
221+
WiFiClient c = server.available();
222+
c.stop();
223+
}
224+
225+
// Loop over clients connect and read available data
226+
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
227+
{
228+
while(clients[i].connected() && clients[i].available())
229+
{
230+
char inChar = clients[i].read();
231+
if ( inputString[i].idx < MAX_RECEIVE_LENGTH - 1 )
232+
{
233+
// if newline then command is complete
234+
if (inChar == '\n')
235+
{
236+
// a command was issued by the client
237+
// we will now try to send it to the actuator
238+
inputString[i].string[inputString[i].idx] = 0;
239+
240+
// echo the string to the serial port
241+
Serial.print("Client "); Serial.print(i); Serial.print(": "); Serial.println(inputString[i].string);
242+
243+
parseAndSend(gw, inputString[i].string);
244+
245+
// clear the string:
246+
inputString[i].idx = 0;
247+
// Finished with this client's message. Next loop() we'll see if there's more to read.
248+
break;
249+
} else {
250+
// add it to the inputString:
251+
inputString[i].string[inputString[i].idx++] = inChar;
252+
}
217253
} else {
218-
// Incoming message too long. Throw away
219-
inputPos = 0;
254+
// Incoming message too long. Throw away
255+
Serial.print("Client "); Serial.print(i); Serial.println(": Message too long");
256+
inputString[i].idx = 0;
257+
// Finished with this client's message. Next loop() we'll see if there's more to read.
258+
break;
220259
}
221260
}
222261
}

libraries/MySensors/examples/Esp8266Gateway/GatewayUtil.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@
33

44
#ifdef ARDUINO
55

6-
76
static uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled
87
static uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode
98

109
#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller
1110
#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller
1211

12+
13+
typedef struct
14+
{
15+
char string[MAX_RECEIVE_LENGTH];
16+
uint8_t idx;
17+
} inputBuffer;
18+
1319
static volatile boolean buttonTriggeredInclusion;
1420
static boolean inclusionMode; // Keeps track on inclusion mode
1521
bool inclusionButtonSupported = false;
@@ -20,7 +26,6 @@ MyParserSerial parser;
2026
void setInclusionMode(boolean newMode);
2127

2228
char convBuf[MAX_PAYLOAD*2+1];
23-
char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera
2429
unsigned long inclusionStartTime;
2530

2631

0 commit comments

Comments
 (0)