diff --git a/Network.cpp b/Network.cpp index 56809a9..ba96111 100644 --- a/Network.cpp +++ b/Network.cpp @@ -54,11 +54,10 @@ void Network::loop() { this->emitSockets(); if(!this->connected()) return; } - if(this->connected() && millis() - this->lastMDNS > 60000) { + if(this->connected() && millis() - this->lastMDNS > 10000) { if(this->lastMDNS != 0) MDNS.setInstanceName(settings.hostname); this->lastMDNS = millis(); } - sockEmit.loop(); if(settings.ssdpBroadcast) { if(!SSDP.isStarted) SSDP.begin(); SSDP.loop(); @@ -74,6 +73,7 @@ void Network::emitSockets() { sockEmit.sendToClients("wifiStrength", buf); this->lastRSSI = WiFi.RSSI(); this->lastChannel = WiFi.channel(); + sockEmit.loop(); } } else { @@ -81,6 +81,7 @@ void Network::emitSockets() { sockEmit.sendToClients("wifiStrength", "{\"ssid\":\"\", \"strength\":-100,\"channel\":-1}"); this->lastRSSI = -100; this->lastChannel = -1; + sockEmit.loop(); } } } diff --git a/Somfy.cpp b/Somfy.cpp index 8406756..df778e2 100644 --- a/Somfy.cpp +++ b/Somfy.cpp @@ -1307,8 +1307,11 @@ void SomfyShade::emitCommand(uint8_t num, somfy_commands cmd, const char *source e.appendMessage(buf); snprintf(buf, sizeof(buf), ",\"source\":\"%s\"", source); e.appendMessage(buf); + snprintf(buf, sizeof(buf), ",\"rcode\":%d", this->lastRollingCode); + e.appendMessage(buf); snprintf(buf, sizeof(buf), ",\"sourceAddress\":%d}", sourceAddress); e.appendMessage(buf); + if(num >= 255) sockEmit.sendToClients(&e); else sockEmit.sendToClient(num, &e); } @@ -2514,32 +2517,48 @@ somfy_commands SomfyRemote::transformCommand(somfy_commands cmd) { } void SomfyRemote::sendCommand(somfy_commands cmd) { this->sendCommand(cmd, this->repeats); } void SomfyRemote::sendCommand(somfy_commands cmd, uint8_t repeat) { - somfy_frame_t frame; - frame.rollingCode = this->getNextRollingCode(); - frame.remoteAddress = this->getRemoteAddress(); - frame.cmd = this->transformCommand(cmd); - frame.repeats = repeat; - frame.bitLength = this->bitLength; + this->lastFrame.rollingCode = this->getNextRollingCode(); + this->lastFrame.remoteAddress = this->getRemoteAddress(); + this->lastFrame.cmd = this->transformCommand(cmd); + this->lastFrame.repeats = repeat; + this->lastFrame.bitLength = this->bitLength; // Match the encKey to the rolling code. These keys range from 160 to 175. - frame.encKey = 0xA0 | static_cast(frame.rollingCode & 0x000F); - frame.proto = this->proto; - if(frame.bitLength == 0) frame.bitLength = bit_length; - this->lastRollingCode = frame.rollingCode; - somfy.sendFrame(frame, repeat); - somfy.processFrame(frame, true); + this->lastFrame.encKey = 0xA0 | static_cast(this->lastFrame.rollingCode & 0x000F); + this->lastFrame.proto = this->proto; + if(this->lastFrame.bitLength == 0) this->lastFrame.bitLength = bit_length; + if(this->lastFrame.rollingCode == 0) Serial.println("ERROR: Setting rcode to 0"); + this->lastRollingCode = this->lastFrame.rollingCode; + Serial.print("CMD:"); + Serial.print(translateSomfyCommand(this->lastFrame.cmd)); + Serial.print(" ADDR:"); + Serial.print(this->lastFrame.remoteAddress); + Serial.print(" RCODE:"); + Serial.print(this->lastFrame.rollingCode); + Serial.print(" REPEAT:"); + Serial.println(repeat); + somfy.sendFrame(this->lastFrame, repeat); + somfy.processFrame(this->lastFrame, true); +} +bool SomfyRemote::isLastCommand(somfy_commands cmd) { + if(this->lastFrame.cmd != cmd || this->lastFrame.rollingCode != this->lastRollingCode) { + Serial.printf("Not the last command %d: %d - %d\n", static_cast(this->lastFrame.cmd), this->lastFrame.rollingCode, this->lastRollingCode); + return false; + } + return true; +} +void SomfyRemote::repeatFrame(uint8_t repeat) { + somfy.transceiver.beginTransmit(); + byte frm[10]; + this->lastFrame.encodeFrame(frm); + somfy.transceiver.sendFrame(frm, this->bitLength == 56 ? 2 : 12, this->bitLength); + for(uint8_t i = 0; i < repeat; i++) { + somfy.transceiver.sendFrame(frm, this->bitLength == 56 ? 7 : 6, this->bitLength); + } + somfy.transceiver.endTransmit(); + //somfy.processFrame(this->lastFrame, true); } void SomfyShadeController::sendFrame(somfy_frame_t &frame, uint8_t repeat) { somfy.transceiver.beginTransmit(); - //Serial.println("----------- Sending Raw -------------"); - Serial.print("CMD:"); - Serial.print(translateSomfyCommand(frame.cmd)); - Serial.print(" ADDR:"); - Serial.print(frame.remoteAddress); - Serial.print(" RCODE:"); - Serial.print(frame.rollingCode); - Serial.print(" REPEAT:"); - Serial.println(repeat); - byte frm[10]; frame.encodeFrame(frm); this->transceiver.sendFrame(frm, frame.bitLength == 56 ? 2 : 12, frame.bitLength); @@ -2604,6 +2623,7 @@ uint16_t SomfyRemote::getNextRollingCode() { pref.putUShort(this->m_remotePrefId, code); pref.end(); this->lastRollingCode = code; + Serial.printf("Getting Next Rolling code %d\n", this->lastRollingCode); return code; } uint16_t SomfyRemote::setRollingCode(uint16_t code) { @@ -2612,6 +2632,7 @@ uint16_t SomfyRemote::setRollingCode(uint16_t code) { pref.putUShort(this->m_remotePrefId, code); pref.end(); this->lastRollingCode = code; + Serial.printf("Setting Last Rolling code %d\n", this->lastRollingCode); } return code; } @@ -3035,15 +3056,15 @@ void Transceiver::clearReceived(void) { attachInterrupt(interruptPin, handleReceive, CHANGE); } void Transceiver::enableReceive(void) { + uint32_t timing = millis(); if(rxmode > 0) return; if(this->config.enabled) { - Serial.print("Enabling receive on Pin #"); - Serial.println(this->config.RXPin); rxmode = 1; pinMode(this->config.RXPin, INPUT); interruptPin = digitalPinToInterrupt(this->config.RXPin); ELECHOUSE_cc1101.SetRx(); attachInterrupt(interruptPin, handleReceive, CHANGE); + Serial.printf("Enabled receive on Pin #%d Timing: %d\n", this->config.RXPin, millis() - timing); } } void Transceiver::disableReceive(void) { @@ -3382,7 +3403,7 @@ void Transceiver::beginTransmit() { void Transceiver::endTransmit() { if(this->config.enabled) { ELECHOUSE_cc1101.setSidle(); - delay(100); + //delay(100); this->enableReceive(); } } diff --git a/Somfy.h b/Somfy.h index 3a9214f..324cbcf 100644 --- a/Somfy.h +++ b/Somfy.h @@ -175,21 +175,24 @@ class SomfyRemote { uint32_t m_remoteAddress = 0; public: radio_proto proto = radio_proto::RTS; + somfy_frame_t lastFrame; bool flipCommands = false; + uint16_t lastRollingCode = 0; uint8_t flags = 0; uint8_t bitLength = 0; uint8_t repeats = 1; + virtual bool isLastCommand(somfy_commands cmd); char *getRemotePrefId() {return m_remotePrefId;} virtual bool toJSON(JsonObject &obj); virtual void setRemoteAddress(uint32_t address); virtual uint32_t getRemoteAddress(); virtual uint16_t getNextRollingCode(); virtual uint16_t setRollingCode(uint16_t code); - uint16_t lastRollingCode = 0; bool hasSunSensor(); void setSunSensor(bool bHasSensor); virtual void sendCommand(somfy_commands cmd); virtual void sendCommand(somfy_commands cmd, uint8_t repeat); + void repeatFrame(uint8_t repeat); somfy_commands transformCommand(somfy_commands cmd); }; class SomfyLinkedRemote : public SomfyRemote { @@ -222,7 +225,6 @@ class SomfyShade : public SomfyRemote { tilt_types tiltType = tilt_types::none; void load(); somfy_tx_queue_t txQueue; - somfy_frame_t lastFrame; float currentPos = 0.0f; float currentTiltPos = 0.0f; //uint16_t movement = 0; diff --git a/SomfyController.ino b/SomfyController.ino index f4e4db6..922adae 100644 --- a/SomfyController.ino +++ b/SomfyController.ino @@ -42,11 +42,21 @@ void loop() { Serial.println("ms"); ESP.restart(); } + uint32_t timing = millis(); net.loop(); + if(millis() - timing > 100) Serial.printf("Timing Net: %dms\n", millis() - timing); + timing = millis(); somfy.loop(); + if(millis() - timing > 100) Serial.printf("Timing Somfy: %dms\n", millis() - timing); + timing = millis(); if(net.connected()) { webServer.loop(); + if(millis() - timing > 200) Serial.printf("Timing WebServer: %dms\n", millis() - timing); + timing = millis(); sockEmit.loop(); + if(millis() - timing > 100) Serial.printf("Timing Socket: %dms\n", millis() - timing); + timing = millis(); + } if(rebootDelay.reboot && millis() > rebootDelay.rebootTime) { net.end(); diff --git a/SomfyController.ino.esp32.bin b/SomfyController.ino.esp32.bin index bbb3d6c..3ea87cd 100644 Binary files a/SomfyController.ino.esp32.bin and b/SomfyController.ino.esp32.bin differ diff --git a/SomfyController.littlefs.bin b/SomfyController.littlefs.bin index 366f4b4..da1e8ef 100644 Binary files a/SomfyController.littlefs.bin and b/SomfyController.littlefs.bin differ diff --git a/Web.cpp b/Web.cpp index 5863857..aa3afce 100644 --- a/Web.cpp +++ b/Web.cpp @@ -35,10 +35,13 @@ void Web::startup() { Serial.println("Launching web server..."); } void Web::loop() { - apiServer.handleClient(); server.handleClient(); + yield(); + apiServer.handleClient(); } -void Web::sendCORSHeaders() { +void Web::sendCORSHeaders(WebServer &server) { + //server.sendHeader(F("Connection"), F("Keep-Alive")); + //server.sendHeader(F("Keep-Alive"), F("timeout=5, max=1000")); //server.sendHeader(F("Access-Control-Allow-Origin"), F("*")); //server.sendHeader(F("Access-Control-Max-Age"), F("600")); //server.sendHeader(F("Access-Control-Allow-Methods"), F("PUT,POST,GET,OPTIONS")); @@ -111,7 +114,7 @@ void Web::handleLogout(WebServer &server) { server.send(301); } void Web::handleLogin(WebServer &server) { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } StaticJsonDocument<256> doc; JsonObject obj = doc.to(); @@ -193,7 +196,7 @@ void Web::handleLogin(WebServer &server) { return; } void Web::handleStreamFile(WebServer &server, const char *filename, const char *encoding) { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); // Load the index html page from the data directory. Serial.print("Loading file "); Serial.println(filename); @@ -207,7 +210,7 @@ void Web::handleStreamFile(WebServer &server, const char *filename, const char * file.close(); } void Web::handleController(WebServer &server) { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_POST || method == HTTP_GET) { @@ -219,7 +222,7 @@ void Web::handleController(WebServer &server) { else server.send(404, _encoding_text, _response_404); } void Web::handleLoginContext(WebServer &server) { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } DynamicJsonDocument doc(512); JsonObject obj = doc.to(); @@ -233,7 +236,7 @@ void Web::handleLoginContext(WebServer &server) { server.send(200, _encoding_json, g_content); } void Web::handleGetShades(WebServer &server) { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_POST || method == HTTP_GET) { @@ -246,7 +249,7 @@ void Web::handleGetShades(WebServer &server) { else server.send(404, _encoding_text, _response_404); } void Web::handleGetGroups(WebServer &server) { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_POST || method == HTTP_GET) { @@ -258,6 +261,158 @@ void Web::handleGetGroups(WebServer &server) { } else server.send(404, _encoding_text, _response_404); } +void Web::handleShadeCommand(WebServer& server) { + webServer.sendCORSHeaders(server); + if (server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } + HTTPMethod method = server.method(); + uint8_t shadeId = 255; + uint8_t target = 255; + int8_t repeat = -1; + somfy_commands command = somfy_commands::My; + if (method == HTTP_GET || method == HTTP_PUT || method == HTTP_POST) { + if (server.hasArg("shadeId")) { + shadeId = atoi(server.arg("shadeId").c_str()); + if (server.hasArg("command")) command = translateSomfyCommand(server.arg("command")); + else if (server.hasArg("target")) target = atoi(server.arg("target").c_str()); + if (server.hasArg("repeat")) repeat = atoi(server.arg("repeat").c_str()); + } + else if (server.hasArg("plain")) { + Serial.println("Sending Shade Command"); + DynamicJsonDocument doc(256); + DeserializationError err = deserializeJson(doc, server.arg("plain")); + if (err) { + switch (err.code()) { + case DeserializationError::InvalidInput: + server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Invalid JSON payload\"}")); + break; + case DeserializationError::NoMemory: + server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Out of memory parsing JSON\"}")); + break; + default: + server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"General JSON Deserialization failed\"}")); + break; + } + return; + } + else { + JsonObject obj = doc.as(); + if (obj.containsKey("shadeId")) shadeId = obj["shadeId"]; + else server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No shade id was supplied.\"}")); + if (obj.containsKey("command")) { + String scmd = obj["command"]; + command = translateSomfyCommand(scmd); + } + else if (obj.containsKey("target")) { + target = obj["target"].as(); + } + if (obj.containsKey("repeat")) repeat = obj["repeat"].as(); + } + } + else server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No shade object supplied.\"}")); + } + SomfyShade* shade = somfy.getShadeById(shadeId); + if (shade) { + Serial.print("Received:"); + Serial.println(server.arg("plain")); + // Send the command to the shade. + if (target <= 100) + shade->moveToTarget(shade->transformPosition(target)); + else if (repeat > 0) + shade->sendCommand(command, repeat); + else + shade->sendCommand(command); + DynamicJsonDocument sdoc(512); + JsonObject sobj = sdoc.to(); + shade->toJSON(sobj); + serializeJson(sdoc, g_content); + server.send(200, _encoding_json, g_content); + } + else { + server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Shade with the specified id not found.\"}")); + } +} +void Web::handleRepeatCommand(WebServer& server) { + webServer.sendCORSHeaders(server); + HTTPMethod method = server.method(); + if (method == HTTP_OPTIONS) { server.send(200, "OK"); return; } + uint8_t shadeId = 255; + uint8_t groupId = 255; + uint8_t target = 255; + int8_t repeat = -1; + somfy_commands command = somfy_commands::My; + if (method == HTTP_GET || method == HTTP_PUT || method == HTTP_POST) { + if(server.hasArg("shadeId")) shadeId = atoi(server.arg("shadeId").c_str()); + else if(server.hasArg("groupId")) shadeId = atoi(server.arg("groupId").c_str()); + if(server.hasArg("command")) command = translateSomfyCommand(server.arg("command")); + if(server.hasArg("repeat")) repeat = atoi(server.arg("repeat").c_str()); + if(shadeId == 255 && groupId == 255 && server.hasArg("plain")) { + DynamicJsonDocument doc(256); + DeserializationError err = deserializeJson(doc, server.arg("plain")); + if (err) { + switch (err.code()) { + case DeserializationError::InvalidInput: + server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Invalid JSON payload\"}")); + break; + case DeserializationError::NoMemory: + server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Out of memory parsing JSON\"}")); + break; + default: + server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"General JSON Deserialization failed\"}")); + break; + } + return; + } + else { + JsonObject obj = doc.as(); + if (obj.containsKey("shadeId")) shadeId = obj["shadeId"]; + if(obj.containsKey("groupId")) groupId = obj["groupId"]; + if (obj.containsKey("command")) { + String scmd = obj["command"]; + command = translateSomfyCommand(scmd); + } + if (obj.containsKey("repeat")) repeat = obj["repeat"].as(); + } + } + DynamicJsonDocument sdoc(512); + JsonObject sobj = sdoc.to(); + if(shadeId != 255) { + SomfyShade *shade = somfy.getShadeById(shadeId); + if(!shade) { + server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Shade reference could not be found.\"}")); + return; + } + if(!shade->isLastCommand(command)) { + // We are going to send this as a new command. + shade->sendCommand(command, repeat >= 0 ? repeat : shade->repeats); + } + else { + shade->repeatFrame(repeat >= 0 ? repeat : shade->repeats); + } + shade->toJSON(sobj); + serializeJson(sdoc, g_content); + server.send(200, _encoding_json, g_content); + } + else if(groupId != 255) { + SomfyGroup * group = somfy.getGroupById(groupId); + if(!group) { + server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Group reference could not be found.\"}")); + return; + } + if(!group->isLastCommand(command)) { + // We are going to send this as a new command. + group->sendCommand(command, repeat >= 0 ? repeat : group->repeats); + } + else + group->repeatFrame(repeat >= 0 ? repeat : group->repeats); + group->toJSON(sobj); + serializeJson(sdoc, g_content); + server.send(200, _encoding_json, g_content); + } + } + else { + server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Invalid Http method\"}")); + } +} void Web::begin() { Serial.println("Creating Web MicroServices..."); server.enableCORS(true); @@ -318,7 +473,7 @@ void Web::begin() { }); apiServer.on("/controller", []() { webServer.handleController(apiServer); }); apiServer.on("/shadeCommand", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(apiServer); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = apiServer.method(); uint8_t shadeId = 255; @@ -388,7 +543,7 @@ void Web::begin() { } }); apiServer.on("/groupCommand", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(apiServer); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = apiServer.method(); uint8_t groupId = 255; @@ -449,7 +604,7 @@ void Web::begin() { } }); apiServer.on("/tiltCommand", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(apiServer); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = apiServer.method(); uint8_t shadeId = 255; @@ -523,7 +678,7 @@ void Web::begin() { server.on("/shades.cfg", []() { webServer.handleStreamFile(server, "/shades.cfg", _encoding_text); }); server.on("/shades.tmp", []() { webServer.handleStreamFile(server, "/shades.tmp", _encoding_text); }); server.on("/backup", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); char filename[120]; Timestamp ts; char * iso = ts.getISOTime(); @@ -553,7 +708,7 @@ void Web::begin() { file.close(); }); server.on("/restore", HTTP_POST, []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); server.sendHeader("Connection", "close"); server.send(200, _encoding_json, "{\"status\":\"Success\",\"desc\":\"Restoring Shade settings\"}"); }, []() { @@ -583,8 +738,8 @@ void Web::begin() { server.on("/favicon.png", []() { webServer.sendCacheHeaders(604800); webServer.handleStreamFile(server, "/favicon.png", "image/png"); }); server.on("/icon.png", []() { webServer.sendCacheHeaders(604800); webServer.handleStreamFile(server, "/icon.png", "image/png"); }); server.onNotFound([]() { - Serial.print("Request 404:"); HTTPMethod method = server.method(); + Serial.printf("Request %s 404-%d ", server.uri().c_str(), method); switch (method) { case HTTP_POST: Serial.print("POST "); @@ -596,7 +751,7 @@ void Web::begin() { Serial.print("PUT "); break; case HTTP_OPTIONS: - Serial.print("OPTIONS "); + Serial.println("OPTIONS "); server.send(200, "OK"); return; default: @@ -613,7 +768,7 @@ void Web::begin() { server.on("/shades", []() { webServer.handleGetShades(server); }); server.on("/groups", []() { webServer.handleGetGroups(server); }); server.on("/getNextShade", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } StaticJsonDocument<256> doc; uint8_t shadeId = somfy.getNextShadeId(); @@ -627,7 +782,7 @@ void Web::begin() { server.send(200, _encoding_json, g_content); }); server.on("/getNextGroup", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); StaticJsonDocument<256> doc; if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } uint8_t groupId = somfy.getNextGroupId(); @@ -751,7 +906,7 @@ void Web::begin() { } }); server.on("/shade", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_GET) { @@ -812,7 +967,7 @@ void Web::begin() { } }); server.on("/group", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_GET) { @@ -873,7 +1028,7 @@ void Web::begin() { } }); server.on("/groupOptions", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_GET || method == HTTP_POST) { @@ -913,7 +1068,7 @@ void Web::begin() { }); server.on("/saveShade", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_PUT || method == HTTP_POST) { @@ -957,7 +1112,7 @@ void Web::begin() { } }); server.on("/saveGroup", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_PUT || method == HTTP_POST) { @@ -1001,7 +1156,7 @@ void Web::begin() { } }); server.on("/tiltCommand", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); uint8_t shadeId = 255; @@ -1065,78 +1220,10 @@ void Web::begin() { server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Shade with the specified id not found.\"}")); } }); - server.on("/shadeCommand", []() { - webServer.sendCORSHeaders(); - if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } - HTTPMethod method = server.method(); - uint8_t shadeId = 255; - uint8_t target = 255; - int8_t repeat = -1; - somfy_commands command = somfy_commands::My; - if (method == HTTP_GET || method == HTTP_PUT || method == HTTP_POST) { - if (server.hasArg("shadeId")) { - shadeId = atoi(server.arg("shadeId").c_str()); - if (server.hasArg("command")) command = translateSomfyCommand(server.arg("command")); - else if(server.hasArg("target")) target = atoi(server.arg("target").c_str()); - if(server.hasArg("repeat")) repeat = atoi(server.arg("repeat").c_str()); - } - else if (server.hasArg("plain")) { - Serial.println("Sending Shade Command"); - DynamicJsonDocument doc(256); - DeserializationError err = deserializeJson(doc, server.arg("plain")); - if (err) { - switch (err.code()) { - case DeserializationError::InvalidInput: - server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Invalid JSON payload\"}")); - break; - case DeserializationError::NoMemory: - server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Out of memory parsing JSON\"}")); - break; - default: - server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"General JSON Deserialization failed\"}")); - break; - } - return; - } - else { - JsonObject obj = doc.as(); - if (obj.containsKey("shadeId")) shadeId = obj["shadeId"]; - else server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No shade id was supplied.\"}")); - if (obj.containsKey("command")) { - String scmd = obj["command"]; - command = translateSomfyCommand(scmd); - } - else if(obj.containsKey("target")) { - target = obj["target"].as(); - } - if(obj.containsKey("repeat")) repeat = obj["repeat"].as(); - } - } - else server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No shade object supplied.\"}")); - } - SomfyShade* shade = somfy.getShadeById(shadeId); - if (shade) { - Serial.print("Received:"); - Serial.println(server.arg("plain")); - // Send the command to the shade. - if(target <= 100) - shade->moveToTarget(shade->transformPosition(target)); - else if(repeat > 0) - shade->sendCommand(command, repeat); - else - shade->sendCommand(command); - DynamicJsonDocument sdoc(512); - JsonObject sobj = sdoc.to(); - shade->toJSON(sobj); - serializeJson(sdoc, g_content); - server.send(200, _encoding_json, g_content); - } - else { - server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Shade with the specified id not found.\"}")); - } - }); + server.on("/repeatCommand", []() { webServer.handleRepeatCommand(server); }); + server.on("/shadeCommand", []() { webServer.handleShadeCommand(server); }); server.on("/groupCommand", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); uint8_t groupId = 255; @@ -1197,7 +1284,7 @@ void Web::begin() { } }); server.on("/setMyPosition", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); uint8_t shadeId = 255; @@ -1254,7 +1341,7 @@ void Web::begin() { } }); server.on("/setRollingCode", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_PUT || method == HTTP_POST) { @@ -1303,7 +1390,7 @@ void Web::begin() { } }); server.on("/setPaired", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } uint8_t shadeId = 255; bool paired = false; @@ -1349,7 +1436,7 @@ void Web::begin() { } }); server.on("/unpairShade", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_PUT || method == HTTP_POST) { @@ -1399,7 +1486,7 @@ void Web::begin() { } }); server.on("/unlinkRemote", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_PUT || method == HTTP_POST) { @@ -1446,7 +1533,7 @@ void Web::begin() { } }); server.on("/linkRemote", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_PUT || method == HTTP_POST) { @@ -1495,7 +1582,7 @@ void Web::begin() { } }); server.on("/linkToGroup", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_PUT || method == HTTP_POST) { @@ -1550,7 +1637,7 @@ void Web::begin() { } }); server.on("/unlinkFromGroup", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_PUT || method == HTTP_POST) { @@ -1605,7 +1692,7 @@ void Web::begin() { } }); server.on("/deleteShade", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); uint8_t shadeId = 255; @@ -1649,7 +1736,7 @@ void Web::begin() { } }); server.on("/deleteGroup", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); uint8_t groupId = 255; @@ -1690,7 +1777,7 @@ void Web::begin() { } }); server.on("/updateFirmware", HTTP_POST, []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); somfy.transceiver.end(); // Shut down the radio so we do not get any interrupts during this process. if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } if (Update.hasError()) @@ -1723,7 +1810,7 @@ void Web::begin() { } }); server.on("/updateShadeConfig", HTTP_POST, []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } server.sendHeader("Connection", "close"); server.send(200, _encoding_json, "{\"status\":\"ERROR\",\"desc\":\"Updating Shade Config: \"}"); @@ -1747,7 +1834,7 @@ void Web::begin() { } }); server.on("/updateApplication", HTTP_POST, []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); somfy.transceiver.end(); // Shut down the radio so we do not get any interrupts during this process. if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } server.sendHeader("Connection", "close"); @@ -1779,7 +1866,7 @@ void Web::begin() { } }); server.on("/scanaps", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); int statusCode = 200; int n = WiFi.scanNetworks(); Serial.print("Scanned "); @@ -1815,7 +1902,7 @@ void Web::begin() { server.send(statusCode, "application/json", g_content); }); server.on("/reboot", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_POST || method == HTTP_PUT) { @@ -1829,7 +1916,7 @@ void Web::begin() { } }); server.on("/saveSecurity", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } DynamicJsonDocument doc(512); DeserializationError err = deserializeJson(doc, server.arg("plain")); @@ -1860,7 +1947,7 @@ void Web::begin() { } }); server.on("/getSecurity", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); DynamicJsonDocument doc(512); JsonObject obj = doc.to(); settings.Security.toJSON(obj); @@ -1868,7 +1955,7 @@ void Web::begin() { server.send(200, _encoding_json, g_content); }); server.on("/saveRadio", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } DynamicJsonDocument doc(512); DeserializationError err = deserializeJson(doc, server.arg("plain")); @@ -1897,7 +1984,7 @@ void Web::begin() { } }); server.on("/getRadio", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); DynamicJsonDocument doc(1024); JsonObject obj = doc.to(); somfy.transceiver.toJSON(obj); @@ -1905,7 +1992,7 @@ void Web::begin() { server.send(200, _encoding_json, g_content); }); server.on("/sendRemoteCommand", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } HTTPMethod method = server.method(); if (method == HTTP_GET || method == HTTP_PUT || method == HTTP_POST) { @@ -1955,7 +2042,7 @@ void Web::begin() { } }); server.on("/setgeneral", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } DynamicJsonDocument doc(512); @@ -1990,7 +2077,7 @@ void Web::begin() { } }); server.on("/setNetwork", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } DynamicJsonDocument doc(1024); DeserializationError err = deserializeJson(doc, server.arg("plain")); @@ -2039,7 +2126,7 @@ void Web::begin() { } }); server.on("/setIP", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } Serial.println("Setting IP..."); DynamicJsonDocument doc(1024); @@ -2064,7 +2151,7 @@ void Web::begin() { } }); server.on("/connectwifi", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); if(server.method() == HTTP_OPTIONS) { server.send(200, "OK"); return; } Serial.println("Settings WIFI connection..."); DynamicJsonDocument doc(512); @@ -2110,7 +2197,7 @@ void Web::begin() { } }); server.on("/modulesettings", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); DynamicJsonDocument doc(512); JsonObject obj = doc.to(); doc["fwVersion"] = settings.fwVersion; @@ -2122,7 +2209,7 @@ void Web::begin() { server.send(200, _encoding_json, g_content); }); server.on("/networksettings", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); DynamicJsonDocument doc(2048); JsonObject obj = doc.to(); doc["fwVersion"] = settings.fwVersion; @@ -2169,7 +2256,7 @@ void Web::begin() { } }); server.on("/mqttsettings", []() { - webServer.sendCORSHeaders(); + webServer.sendCORSHeaders(server); DynamicJsonDocument doc(1024); JsonObject obj = doc.to(); settings.MQTT.toJSON(obj); diff --git a/Web.h b/Web.h index fccbbad..460dbcc 100644 --- a/Web.h +++ b/Web.h @@ -3,7 +3,7 @@ #define webserver_h class Web { public: - void sendCORSHeaders(); + void sendCORSHeaders(WebServer &server); void sendCacheHeaders(uint32_t seconds=604800); void startup(); void handleLogin(WebServer &server); @@ -13,6 +13,8 @@ class Web { void handleLoginContext(WebServer &server); void handleGetShades(WebServer &server); void handleGetGroups(WebServer &server); + void handleShadeCommand(WebServer &server); + void handleRepeatCommand(WebServer &server); void begin(); void loop(); void end(); diff --git a/data/index.html b/data/index.html index c49455b..e871aac 100644 --- a/data/index.html +++ b/data/index.html @@ -398,6 +398,19 @@ + + + + + + + + + + + + + @@ -653,6 +666,7 @@