#include #include #include #include "Sockets.h" #include "ConfigSettings.h" #include "Somfy.h" #include "Network.h" #include "GitOTA.h" extern ConfigSettings settings; extern Network net; extern SomfyShadeController somfy; extern SocketEmitter sockEmit; extern GitUpdater git; WebSocketsServer sockServer = WebSocketsServer(8080); #define MAX_SOCK_RESPONSE 2048 static char g_response[MAX_SOCK_RESPONSE]; bool room_t::isJoined(uint8_t num) { for(uint8_t i = 0; i < sizeof(this->clients); i++) { if(this->clients[i] == num) return true; } return false; } bool room_t::join(uint8_t num) { if(this->isJoined(num)) return true; for(uint8_t i = 0; i < sizeof(this->clients); i++) { if(this->clients[i] == 255) { this->clients[i] = num; return true; } } return false; } bool room_t::leave(uint8_t num) { if(!this->isJoined(num)) return false; for(uint8_t i = 0; i < sizeof(this->clients); i++) { if(this->clients[i] == num) this->clients[i] = 255; } return true; } uint8_t room_t::activeClients() { uint8_t n = 0; for(uint8_t i = 0; i < sizeof(this->clients); i++) { if(this->clients[i] != 255) n++; } return n; } /********************************************************************* * ClientSocketEvent class members ********************************************************************/ /* void ClientSocketEvent::prepareMessage(const char *evt, const char *payload) { if(strlen(payload) + 5 >= sizeof(this->msg)) Serial.printf("Socket buffer overflow %d > 2048\n", strlen(payload) + 5 + strlen(evt)); snprintf(this->msg, sizeof(this->msg), "42[%s,%s]", evt, payload); } void ClientSocketEvent::prepareMessage(const char *evt, JsonDocument &doc) { memset(this->msg, 0x00, sizeof(this->msg)); snprintf(this->msg, sizeof(this->msg), "42[%s,", evt); serializeJson(doc, &this->msg[strlen(this->msg)], sizeof(this->msg) - strlen(this->msg) - 2); strcat(this->msg, "]"); } */ /********************************************************************* * SocketEmitter class members ********************************************************************/ void SocketEmitter::startup() { } void SocketEmitter::begin() { sockServer.begin(); sockServer.enableHeartbeat(20000, 10000, 3); sockServer.onEvent(this->wsEvent); Serial.println("Socket Server Started..."); settings.printAvailHeap(); } void SocketEmitter::loop() { sockServer.loop(); } /* ClientSocketEvent::ClientSocketEvent() { this->msg[0] = 0x00; } ClientSocketEvent::ClientSocketEvent(const char *evt) { snprintf(this->msg, sizeof(this->msg), "42[%s,]", evt); } //ClientSocketEvent::ClientSocketEvent(const char *evt, const char *payload) { snprintf(this->msg, sizeof(this->msg), "42[%s,%s]", evt, payload); } void ClientSocketEvent::beginEmit(const char *evt) { snprintf(this->msg, sizeof(this->msg), "42[%s,", evt); } void ClientSocketEvent::endEmit() { this->_safecat("]"); } void ClientSocketEvent::appendMessage(const char *text) { uint16_t len = strlen(this->msg); this->msg[len - 1] = '\0'; strcat(this->msg, text); strcat(this->msg, "]"); } void ClientSocketEvent::beginObject(const char *name) { if(name && strlen(name) > 0) this->appendElem(name); else if(!this->_nocomma) this->_safecat(","); this->_safecat("{"); this->_objects++; this->_nocomma = true; } void ClientSocketEvent::endObject() { //if(strlen(this->buff) + 1 > this->buffSize - 1) this->send(); this->_safecat("}"); this->_objects--; this->_nocomma = false; } void ClientSocketEvent::beginArray(const char *name) { if(name && strlen(name) > 0) this->appendElem(name); else if(!this->_nocomma) this->_safecat(","); this->_safecat("["); this->_arrays++; this->_nocomma = true; } void ClientSocketEvent::endArray() { //if(strlen(this->buff) + 1 > this->buffSize - 1) this->send(); this->_safecat("]"); this->_arrays--; this->_nocomma = false; } void ClientSocketEvent::appendElem(const char *name) { if(!this->_nocomma) this->_safecat(","); if(name && strlen(name) > 0) { this->_safecat(name, true); this->_safecat(":"); } this->_nocomma = false; } void ClientSocketEvent::addElem(const char *name, const char *val) { if(!val) return; this->appendElem(name); this->_safecat(val, true); } void ClientSocketEvent::addElem(const char *val) { this->addElem(nullptr, val); } void ClientSocketEvent::addElem(float fval) { sprintf(this->_numbuff, "%.4f", fval); this->_appendNumber(nullptr); } void ClientSocketEvent::addElem(int8_t nval) { sprintf(this->_numbuff, "%d", nval); this->_appendNumber(nullptr); } void ClientSocketEvent::addElem(uint8_t nval) { sprintf(this->_numbuff, "%u", nval); this->_appendNumber(nullptr); } void ClientSocketEvent::addElem(int16_t nval) { sprintf(this->_numbuff, "%d", nval); this->_appendNumber(nullptr); } void ClientSocketEvent::addElem(uint16_t nval) { sprintf(this->_numbuff, "%u", nval); this->_appendNumber(nullptr); } void ClientSocketEvent::addElem(int32_t nval) { sprintf(this->_numbuff, "%ld", (long)nval); this->_appendNumber(nullptr); } void ClientSocketEvent::addElem(uint32_t nval) { sprintf(this->_numbuff, "%lu", (unsigned long)nval); this->_appendNumber(nullptr); } void ClientSocketEvent::addElem(int64_t lval) { sprintf(this->_numbuff, "%lld", (long long)lval); this->_appendNumber(nullptr); } void ClientSocketEvent::addElem(uint64_t lval) { sprintf(this->_numbuff, "%llu", (unsigned long long)lval); this->_appendNumber(nullptr); } void ClientSocketEvent::addElem(bool bval) { strcpy(this->_numbuff, bval ? "true" : "false"); this->_appendNumber(nullptr); } void ClientSocketEvent::addElem(const char *name, float fval) { sprintf(this->_numbuff, "%.4f", fval); this->_appendNumber(name); } void ClientSocketEvent::addElem(const char *name, int8_t nval) { sprintf(this->_numbuff, "%d", nval); this->_appendNumber(name); } void ClientSocketEvent::addElem(const char *name, uint8_t nval) { sprintf(this->_numbuff, "%u", nval); this->_appendNumber(name); } void ClientSocketEvent::addElem(const char *name, int16_t nval) { sprintf(this->_numbuff, "%d", nval); this->_appendNumber(name); } void ClientSocketEvent::addElem(const char *name, uint16_t nval) { sprintf(this->_numbuff, "%u", nval); this->_appendNumber(name); } void ClientSocketEvent::addElem(const char *name, int32_t nval) { sprintf(this->_numbuff, "%ld", (long)nval); this->_appendNumber(name); } void ClientSocketEvent::addElem(const char *name, uint32_t nval) { sprintf(this->_numbuff, "%lu", (unsigned long)nval); this->_appendNumber(name); } void ClientSocketEvent::addElem(const char *name, int64_t lval) { sprintf(this->_numbuff, "%lld", (long long)lval); this->_appendNumber(name); } void ClientSocketEvent::addElem(const char *name, uint64_t lval) { sprintf(this->_numbuff, "%llu", (unsigned long long)lval); this->_appendNumber(name); } void ClientSocketEvent::addElem(const char *name, bool bval) { strcpy(this->_numbuff, bval ? "true" : "false"); this->_appendNumber(name); } void ClientSocketEvent::_safecat(const char *val, bool escape) { size_t len = strlen(val) + strlen(this->msg); if(escape) len += 2; if(len >= sizeof(this->msg)) { //this->send(); } if(escape) strcat(this->msg, "\""); strcat(this->msg, val); if(escape) strcat(this->msg, "\""); } void ClientSocketEvent::_appendNumber(const char *name) { this->appendElem(name); this->_safecat(this->_numbuff); } */ JsonSockEvent *SocketEmitter::beginEmit(const char *evt) { this->json.beginEvent(&sockServer, evt, g_response, sizeof(g_response)); return &this->json; } void SocketEmitter::endEmit(uint8_t num) { sockServer.loop(); this->json.endEvent(num); } void SocketEmitter::endEmitRoom(uint8_t room) { if(room < SOCK_MAX_ROOMS) { room_t *r = &this->rooms[room]; for(uint8_t i = 0; i < sizeof(r->clients); i++) { if(r->clients[i] != 255) this->json.endEvent(r->clients[i]); } } } uint8_t SocketEmitter::activeClients(uint8_t room) { if(room < SOCK_MAX_ROOMS) return this->rooms[room].activeClients(); return 0; } /* bool SocketEmitter::sendToRoom(uint8_t room, ClientSocketEvent *evt) { if(room < SOCK_MAX_ROOMS) { room_t *r = &this->rooms[room]; for(uint8_t i = 0; i < sizeof(r->clients); i++) { if(r->clients[i] != 255) this->sendToClient(r->clients[i], evt); } return true; } return false; } bool SocketEmitter::sendToClients(ClientSocketEvent *evt) { if(evt->msg[strlen(evt->msg) - 1] != ']') strcat(evt->msg, "]"); return sockServer.broadcastTXT(evt->msg); } bool SocketEmitter::sendToClient(uint8_t num, ClientSocketEvent *evt) { if(evt->msg[strlen(evt->msg) - 1] != ']') strcat(evt->msg, "]"); return sockServer.sendTXT(num, evt->msg); } bool SocketEmitter::sendToClients(const char *evt, const char *payload) { if(settings.status == DS_FWUPDATE) return true; this->evt.prepareMessage(evt, payload); return sockServer.broadcastTXT(this->evt.msg); } bool SocketEmitter::sendToClient(uint8_t num, const char *evt, const char *payload) { if(settings.status == DS_FWUPDATE) return true; this->evt.prepareMessage(evt, payload); return sockServer.sendTXT(num, this->evt.msg); } bool SocketEmitter::sendToClient(uint8_t num, const char *evt, JsonDocument &doc) { if(settings.status == DS_FWUPDATE) return true; this->evt.prepareMessage(evt, doc); return sockServer.sendTXT(num, this->evt.msg); } bool SocketEmitter::sendToClients(const char *evt, JsonDocument &doc) { if(settings.status == DS_FWUPDATE) return true; this->evt.prepareMessage(evt, doc); return sockServer.broadcastTXT(this->evt.msg); } */ void SocketEmitter::end() { sockServer.close(); } void SocketEmitter::disconnect() { sockServer.disconnect(); } void SocketEmitter::wsEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) { switch(type) { case WStype_ERROR: if(length > 0) Serial.printf("Socket Error: %s\n", payload); else Serial.println("Socket Error: \n"); break; case WStype_DISCONNECTED: if(length > 0) Serial.printf("Socket [%u] Disconnected!\n [%s]", num, payload); else Serial.printf("Socket [%u] Disconnected!\n", num); for(uint8_t i = 0; i < SOCK_MAX_ROOMS; i++) { sockEmit.rooms[i].leave(num); } break; case WStype_CONNECTED: { IPAddress ip = sockServer.remoteIP(num); Serial.printf("Socket [%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); // Send all the current shade settings to the client. sockServer.sendTXT(num, "Connected"); sockServer.loop(); settings.emitSockets(num); somfy.emitState(num); git.emitUpdateCheck(num); net.emitSockets(num); sockServer.loop(); net.needsBroadcast = true; } break; case WStype_TEXT: if(strncmp((char *)payload, "join:", 5) == 0) { // In this instance the client wants to join a room. Let's do some // work to get the ordinal of the room that the client wants to join. uint8_t roomNum = atoi((char *)&payload[5]); Serial.printf("Client %u joining room %u\n", num, roomNum); if(roomNum < SOCK_MAX_ROOMS) sockEmit.rooms[roomNum].join(num); } else if(strncmp((char *)payload, "leave:", 6) == 0) { uint8_t roomNum = atoi((char *)&payload[6]); Serial.printf("Client %u leaving room %u\n", num, roomNum); if(roomNum < SOCK_MAX_ROOMS) sockEmit.rooms[roomNum].leave(num); } else { Serial.printf("Socket [%u] text: %s\n", num, payload); } // send message to client // webSocket.sendTXT(num, "message here"); // send data to all connected clients // sockServer.broadcastTXT("message here"); break; case WStype_BIN: Serial.printf("[%u] get binary length: %u\n", num, length); //hexdump(payload, length); // send message to client // sockServer.sendBIN(num, payload, length); break; case WStype_PONG: //Serial.printf("Pong from %u\n", num); break; case WStype_PING: //Serial.printf("Ping from %u\n", num); break; default: break; } }