From 448436250e054934a9e0db9b6fdff9e8d663f121 Mon Sep 17 00:00:00 2001 From: StefanoTesla Date: Fri, 3 May 2024 16:59:39 +0200 Subject: [PATCH 1/5] program reorganization lot's of reorganization, don't use! --- .vscode/settings.json | 11 +- platformio.ini | 9 +- src/{ => Alpaca}/alpacamanagefunction.h | 13 +- src/AsyncJson.h | 255 ++++++++++++++ .../alpacaDevice.h} | 83 +---- src/CoverC/alpacaManage.h | 73 ++++ src/CoverC/cover.h | 58 ++++ src/CoverC/coverVariable.h | 32 ++ src/CoverC/webserver.h | 47 +++ .../alpacaDevices.h} | 59 +--- src/Dome/alpacaManage.h | 65 ++++ src/{domehandler.h => Dome/dome.h} | 102 ++++-- src/Dome/domeVariable.h | 68 ++++ src/Dome/webserver.h | 82 +++++ .../alpacaDevice.h} | 192 +++-------- src/Switches/alpacaManage.h | 64 ++++ src/Switches/switch.h | 178 ++++++++++ src/Switches/switchVariable.h | 59 ++++ src/Switches/webserver.h | 142 ++++++++ src/browserServer.h | 314 +++--------------- src/configuration.h | 35 ++ src/dome.cpp | 125 ------- src/fileHandler.h | 180 ---------- src/header.h | 202 +++++------ src/loop.h | 49 +++ src/main.cpp | 116 +++++++ src/switchhandler.h | 65 ---- 27 files changed, 1611 insertions(+), 1067 deletions(-) rename src/{ => Alpaca}/alpacamanagefunction.h (95%) create mode 100644 src/AsyncJson.h rename src/{AlpacaCoverCalibratorServer.h => CoverC/alpacaDevice.h} (52%) create mode 100644 src/CoverC/alpacaManage.h create mode 100644 src/CoverC/cover.h create mode 100644 src/CoverC/coverVariable.h create mode 100644 src/CoverC/webserver.h rename src/{AlpacaDomeServer.h => Dome/alpacaDevices.h} (73%) create mode 100644 src/Dome/alpacaManage.h rename src/{domehandler.h => Dome/dome.h} (66%) create mode 100644 src/Dome/domeVariable.h create mode 100644 src/Dome/webserver.h rename src/{AlpacaSwitchServer.h => Switches/alpacaDevice.h} (54%) create mode 100644 src/Switches/alpacaManage.h create mode 100644 src/Switches/switch.h create mode 100644 src/Switches/switchVariable.h create mode 100644 src/Switches/webserver.h create mode 100644 src/configuration.h delete mode 100644 src/dome.cpp delete mode 100644 src/fileHandler.h create mode 100644 src/loop.h create mode 100644 src/main.cpp delete mode 100644 src/switchhandler.h diff --git a/.vscode/settings.json b/.vscode/settings.json index b027cd1..da7ed8e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,8 +14,15 @@ "ostream": "cpp", "tuple": "cpp", "type_traits": "cpp", - "utility": "cpp" + "utility": "cpp", + "bitset": "cpp", + "string_view": "cpp", + "initializer_list": "cpp", + "regex": "cpp", + "optional": "cpp", + "system_error": "cpp" }, "idf.portWin": "COM3", - "cmake.sourceDirectory": "C:/Users/StefanoMartini/ascom-alpacha-switch-dome-board/.pio/libdeps/esp32doit-devkit-v1/ArduinoJson" + "cmake.sourceDirectory": "C:/Users/StefanoMartini/ascom-alpacha-switch-dome-board/.pio/libdeps/esp32doit-devkit-v1/ArduinoJson", + "C_Cpp.dimInactiveRegions": true } \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index ce85f34..84dbc07 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,7 +14,8 @@ board = esp32doit-devkit-v1 framework = arduino monitor_speed = 115200 lib_deps = - esphome/ESPAsyncWebServer-esphome@3.1.0 - alanswx/ESPAsyncWiFiManager@0.31 - ayushsharma82/AsyncElegantOTA@2.2.8 - bblanchon/ArduinoJson@7.0.2 + esphome/ESPAsyncWebServer-esphome + alanswx/ESPAsyncWiFiManager + ayushsharma82/ElegantOTA + bblanchon/ArduinoJson +build_flags=-DELEGANTOTA_USE_ASYNC_WEBSERVER=1 \ No newline at end of file diff --git a/src/alpacamanagefunction.h b/src/Alpaca/alpacamanagefunction.h similarity index 95% rename from src/alpacamanagefunction.h rename to src/Alpaca/alpacamanagefunction.h index 31255e3..2cc5e35 100644 --- a/src/alpacamanagefunction.h +++ b/src/Alpaca/alpacamanagefunction.h @@ -35,7 +35,8 @@ void GetAlpArguments(AsyncWebServerRequest *request ) { AlpacaData.switches.id = -1; AlpacaData.switches.state = false; AlpacaData.switches.intValue = -1; - AlpacaData.coverCalibrator.brightness = -1; + AlpacaData.coverC.brightness = -1; + AlpacaData.LastServerRequest = millis(); int paramsNr = request->params(); String parameter; AlpacaData.serverTransactionID++; @@ -83,7 +84,7 @@ void GetAlpArguments(AsyncWebServerRequest *request ) { } } if (parameter == "brightness") { - AlpacaData.coverCalibrator.brightness = p->value().toInt(); + AlpacaData.coverC.brightness = p->value().toInt(); } } @@ -159,10 +160,10 @@ void AlpacaManager(){ response->print(F("{\"DeviceName\":\"TeslaSwitch\",\"DeviceType\":\"Switch\",\"DeviceNumber\":0,\"UniqueID\":\"d93f20fb-aa85-49ed-8799-9f50c0969ede\"},")); response->print(F("{\"DeviceName\":\"TeslaCoverCalibratior\",\"DeviceType\":\"CoverCalibrator\",\"DeviceNumber\":0,\"UniqueID\":\"35672690-40bf-4165-b44e-d59c2c524f11\"}")); response->print(F("],")); - response->printf("%s%d,%s%d", - Alp_CliTraId,AlpacaData.clientTransactionID, - Alp_SerTraId,AlpacaData.serverTransactionID - ); + response->printf("%s%d,%s%d", + Alp_CliTraId,AlpacaData.clientTransactionID, + Alp_SerTraId,AlpacaData.serverTransactionID + ); response->print(F("}")); request->send(response); }); diff --git a/src/AsyncJson.h b/src/AsyncJson.h new file mode 100644 index 0000000..b9395a4 --- /dev/null +++ b/src/AsyncJson.h @@ -0,0 +1,255 @@ +// AsyncJson.h +/* + Async Response to use with ArduinoJson and AsyncWebServer + Written by Andrew Melvin (SticilFace) with help from me-no-dev and BBlanchon. + Updtated to ArduinoJson7 by StefanoTesla + Example of callback in use + + server.on("/json", HTTP_ANY, [](AsyncWebServerRequest * request) { + + AsyncJsonResponse * response = new AsyncJsonResponse(); + JsonObject& root = response->getRoot(); + root["key1"] = "key number one"; + JsonObject& nested = root.createNestedObject("nested"); + nested["key1"] = "key number one"; + + response->setLength(); + request->send(response); + }); + + -------------------- + + Async Request to use with ArduinoJson and AsyncWebServer + Written by Arsène von Wyss (avonwyss) + + Example + + AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint"); + handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json) { + JsonObject& jsonObj = json.as(); + // ... + }); + server.addHandler(handler); + +*/ +#ifndef ASYNC_JSON_H_ +#define ASYNC_JSON_H_ +#include +#include +#include + +#if ARDUINOJSON_VERSION_MAJOR == 5 + #define ARDUINOJSON_5_COMPATIBILITY +#else + #ifndef DYNAMIC_JSON_DOCUMENT_SIZE + #define DYNAMIC_JSON_DOCUMENT_SIZE 1024 + #endif +#endif + +constexpr const char* JSON_MIMETYPE = "application/json"; + +/* + * Json Response + * */ + +class ChunkPrint : public Print { + private: + uint8_t* _destination; + size_t _to_skip; + size_t _to_write; + size_t _pos; + public: + ChunkPrint(uint8_t* destination, size_t from, size_t len) + : _destination(destination), _to_skip(from), _to_write(len), _pos{0} {} + virtual ~ChunkPrint(){} + size_t write(uint8_t c){ + if (_to_skip > 0) { + _to_skip--; + return 1; + } else if (_to_write > 0) { + _to_write--; + _destination[_pos++] = c; + return 1; + } + return 0; + } + size_t write(const uint8_t *buffer, size_t size) + { + return this->Print::write(buffer, size); + } +}; + +class AsyncJsonResponse: public AsyncAbstractResponse { + protected: + +#ifdef ARDUINOJSON_5_COMPATIBILITY + DynamicJsonBuffer _jsonBuffer; +#else + JsonDocument _jsonBuffer; +#endif + + JsonVariant _root; + bool _isValid; + + public: + +#ifdef ARDUINOJSON_5_COMPATIBILITY + AsyncJsonResponse(bool isArray=false): _isValid{false} { + _code = 200; + _contentType = JSON_MIMETYPE; + if(isArray) + _root = _jsonBuffer.createArray(); + else + _root = _jsonBuffer.createObject(); + } +#else + AsyncJsonResponse(bool isArray = false, Allocator* allocator = nullptr, bool isValid = false) + : _jsonBuffer(allocator), _isValid(isValid) { + _code = 200; + _contentType = JSON_MIMETYPE; + if(isArray) + _root = _jsonBuffer.add(); + else + _root = _jsonBuffer.add(); + } +#endif + + ~AsyncJsonResponse() {} + JsonVariant & getRoot() { return _root; } + bool _sourceValid() const { return _isValid; } + size_t setLength() { + +#ifdef ARDUINOJSON_5_COMPATIBILITY + _contentLength = _root.measureLength(); +#else + _contentLength = measureJson(_root); +#endif + + if (_contentLength) { _isValid = true; } + return _contentLength; + } + + size_t getSize() { return _jsonBuffer.size(); } + + size_t _fillBuffer(uint8_t *data, size_t len){ + ChunkPrint dest(data, _sentLength, len); + +#ifdef ARDUINOJSON_5_COMPATIBILITY + _root.printTo( dest ) ; +#else + serializeJson(_root, dest); +#endif + return len; + } +}; + +class PrettyAsyncJsonResponse: public AsyncJsonResponse { +public: +#ifdef ARDUINOJSON_5_COMPATIBILITY + PrettyAsyncJsonResponse (bool isArray=false) : AsyncJsonResponse{isArray} {} +#else + PrettyAsyncJsonResponse(bool isArray = false, Allocator* allocator = nullptr) : AsyncJsonResponse(isArray, allocator) {} +#endif + size_t setLength () { +#ifdef ARDUINOJSON_5_COMPATIBILITY + _contentLength = _root.measurePrettyLength (); +#else + _contentLength = measureJsonPretty(_root); +#endif + if (_contentLength) {_isValid = true;} + return _contentLength; + } + size_t _fillBuffer (uint8_t *data, size_t len) { + ChunkPrint dest (data, _sentLength, len); +#ifdef ARDUINOJSON_5_COMPATIBILITY + _root.prettyPrintTo (dest); +#else + serializeJsonPretty(_root, dest); +#endif + return len; + } +}; + +typedef std::function ArJsonRequestHandlerFunction; + +class AsyncCallbackJsonWebHandler: public AsyncWebHandler { +private: +protected: + const String _uri; + WebRequestMethodComposite _method; + ArJsonRequestHandlerFunction _onRequest; + size_t _contentLength; +#ifndef ARDUINOJSON_5_COMPATIBILITY + const size_t maxJsonBufferSize; +#endif + size_t _maxContentLength; +public: +#ifdef ARDUINOJSON_5_COMPATIBILITY + AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest) + : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {} +#else + AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize=DYNAMIC_JSON_DOCUMENT_SIZE) + : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), maxJsonBufferSize(maxJsonBufferSize), _maxContentLength(16384) {} +#endif + + void setMethod(WebRequestMethodComposite method){ _method = method; } + void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; } + void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; } + + virtual bool canHandle(AsyncWebServerRequest *request) override final{ + if(!_onRequest) + return false; + + if(!(_method & request->method())) + return false; + + if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/"))) + return false; + + if ( !request->contentType().equalsIgnoreCase(JSON_MIMETYPE) ) + return false; + + request->addInterestingHeader("ANY"); + return true; + } + + virtual void handleRequest(AsyncWebServerRequest *request) override final { + if(_onRequest) { + if (request->_tempObject != NULL) { + +#ifdef ARDUINOJSON_5_COMPATIBILITY + DynamicJsonBuffer jsonBuffer; + JsonVariant json = jsonBuffer.parse((uint8_t*)(request->_tempObject)); + if (json.success()) { +#else + JsonDocument jsonBuffer;//(this->maxJsonBufferSize); + DeserializationError error = deserializeJson(jsonBuffer, (uint8_t*)(request->_tempObject)); + if(!error) { + JsonVariant json = jsonBuffer.as(); +#endif + + _onRequest(request, json); + return; + } + } + request->send(_contentLength > _maxContentLength ? 413 : 400); + } else { + request->send(500); + } + } + virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final { + } + virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final { + if (_onRequest) { + _contentLength = total; + if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) { + request->_tempObject = malloc(total); + } + if (request->_tempObject != NULL) { + memcpy((uint8_t*)(request->_tempObject) + index, data, len); + } + } + } + virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;} +}; +#endif diff --git a/src/AlpacaCoverCalibratorServer.h b/src/CoverC/alpacaDevice.h similarity index 52% rename from src/AlpacaCoverCalibratorServer.h rename to src/CoverC/alpacaDevice.h index 61461c2..fac33d4 100644 --- a/src/AlpacaCoverCalibratorServer.h +++ b/src/CoverC/alpacaDevice.h @@ -1,14 +1,8 @@ -#ifndef COVER_CALIB -#define COVER_CALIB +#ifndef COVER_ALPACA_DEVICE +#define COVER_ALPACA_DEVICE -void CoverCalibratorSetup() -{ - ledcSetup(0, 5000, 13); - if(setting.coverCalibration.pin){ ledcAttachPin(setting.coverCalibration.pin, 0); } - Serial.println(setting.coverCalibration.pin); -} -void CoverCalibratorServer() +void CoverAlpacaDevice() { Alpserver.on("/api/v1/covercalibrator/0/brightness", HTTP_GET, [](AsyncWebServerRequest *request){ @@ -52,7 +46,7 @@ void CoverCalibratorServer() Alpserver.on("/api/v1/covercalibrator/0/calibratoroff", HTTP_PUT, [](AsyncWebServerRequest *request){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); - ledcWrite(0,0); + coverC.cmdValue = 0; AlpacaHeaderSchema(response,AlpacaData); AlpacaNoErrorSchema(response,false); response->print(F("}")); @@ -63,78 +57,15 @@ void CoverCalibratorServer() GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(AlpacaData.coverCalibrator.brightness < 0 || AlpacaData.coverCalibrator.brightness > 8192){ - response->printf("%s1025,%s\"Brightness value exced limit. %d given, MIN:0 MAX:8192\"",Alp_ErrN,Alp_ErrM,AlpacaData.coverCalibrator.brightness); + if(AlpacaData.coverC.brightness < 0 || AlpacaData.coverC.brightness > 8192){ + response->printf("%s1025,%s\"Brightness value exced limit. %d given, MIN:0 MAX:8192\"",Alp_ErrN,Alp_ErrM,AlpacaData.coverC.brightness); } else { - ledcWrite(0,AlpacaData.coverCalibrator.brightness); + coverC.cmdValue = AlpacaData.coverC.brightness; AlpacaNoErrorSchema(response,false); } response->print(F("}")); request->send(response); }); - - Alpserver.on("/api/v1/covercalibrator/0/connected", HTTP_GET, [](AsyncWebServerRequest *request){ - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->print(F("\"Value\":true}")); - request->send(response); - }); - - Alpserver.on("/api/v1/covercalibrator/0/connected", HTTP_PUT, [](AsyncWebServerRequest *request){ - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response,false); - response->print(F("}")); - request->send(response); - }); - - Alpserver.on("/api/v1/covercalibrator/0/description", HTTP_GET, [](AsyncWebServerRequest *request){ - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->print(F("\"Value\":\"StefanoTesla CoverCalibrator\"}")); - request->send(response); - }); - - Alpserver.on("/api/v1/covercalibrator/0/driverinfo", HTTP_GET, [](AsyncWebServerRequest *request){ - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->print(F("\"Value\":\"StefanoTesla CoverCalibrator response on the fly\"}")); - request->send(response); - }); - - Alpserver.on("/api/v1/covercalibrator/0/driverversion", HTTP_GET, [](AsyncWebServerRequest *request){ - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->print(F("\"Value\":\"2.0.0\"}")); - request->send(response); - }); - - Alpserver.on("/api/v1/covercalibrator/0/interfaceversion", HTTP_GET, [](AsyncWebServerRequest *request){ - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->print(F("\"Value\":1}")); - request->send(response); - }); - - Alpserver.on("/api/v1/covercalibrator/0/name", HTTP_GET, [](AsyncWebServerRequest *request){ - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->print(F("\"Value\":\"StefanoTesla Cover Calibrator\"}")); - request->send(response); - }); Alpserver.on("/api/v1/covercalibrator/0/action", HTTP_PUT, [](AsyncWebServerRequest *request) { GetAlpArguments(request); diff --git a/src/CoverC/alpacaManage.h b/src/CoverC/alpacaManage.h new file mode 100644 index 0000000..af96275 --- /dev/null +++ b/src/CoverC/alpacaManage.h @@ -0,0 +1,73 @@ +#ifndef COVER_ALPACA_MANAGE +#define COVER_ALPACA_MANAGE + + + +void CoverAlpacaManage() +{ + Alpserver.on("/api/v1/covercalibrator/0/connected", HTTP_GET, [](AsyncWebServerRequest *request){ + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->print(F("\"Value\":true}")); + request->send(response); + }); + + Alpserver.on("/api/v1/covercalibrator/0/connected", HTTP_PUT, [](AsyncWebServerRequest *request){ + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response,false); + response->print(F("}")); + request->send(response); + }); + + Alpserver.on("/api/v1/covercalibrator/0/description", HTTP_GET, [](AsyncWebServerRequest *request){ + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->print(F("\"Value\":\"StefanoTesla CoverCalibrator\"}")); + request->send(response); + }); + + Alpserver.on("/api/v1/covercalibrator/0/driverinfo", HTTP_GET, [](AsyncWebServerRequest *request){ + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->print(F("\"Value\":\"StefanoTesla CoverCalibrator response on the fly\"}")); + request->send(response); + }); + + Alpserver.on("/api/v1/covercalibrator/0/driverversion", HTTP_GET, [](AsyncWebServerRequest *request){ + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->print(F("\"Value\":\"2.0.0\"}")); + request->send(response); + }); + + Alpserver.on("/api/v1/covercalibrator/0/interfaceversion", HTTP_GET, [](AsyncWebServerRequest *request){ + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->print(F("\"Value\":1}")); + request->send(response); + }); + + Alpserver.on("/api/v1/covercalibrator/0/name", HTTP_GET, [](AsyncWebServerRequest *request){ + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->print(F("\"Value\":\"StefanoTesla Cover Calibrator\"}")); + request->send(response); + }); + +} + +#endif diff --git a/src/CoverC/cover.h b/src/CoverC/cover.h new file mode 100644 index 0000000..c5225de --- /dev/null +++ b/src/CoverC/cover.h @@ -0,0 +1,58 @@ +#ifndef COVER_HAND +#define COVER_HAND + + +void initCoverCConfig(){ + JsonDocument doc; + File file = SPIFFS.open("/ccalibconfig.txt", FILE_READ); + if (!file) { + Serial.println("Reading Cover Calibrator config error"); + return; + } + DeserializationError error = deserializeJson(doc, file); + + if(error){ + Serial.print(F("deserializeJson() failed: ")); + Serial.println(error.c_str()); + return; + } else { + Config.coverC.pin = doc["pin"]; + } + file.close(); + Config.read.coverC.isValid = true; + ledcSetup(0, 5000, 13); + if(Config.coverC.pin){ ledcAttachPin(Config.coverC.pin, 0); } +} + +void saveCoverCConfig(){ + String datasetup; + JsonDocument doc; + doc["pin"] = Config.coverC.pin; + serializeJson(doc, datasetup); + File file = SPIFFS.open("/ccalibconfig.txt", FILE_WRITE); + file.print(datasetup); + file.close(); +} + + +void coverCLoop(){ + + coverC.actualValue = ledcRead(0); + if (coverC.actualValue != coverC.cmdValue){ + ledcWrite(0 ,coverC.cmdValue); + } +} + + +#include "alpacaDevice.h" +#include "alpacaManage.h" +#include "webserver.h" + +void coverServer(){ + + CoverAlpacaDevice(); + CoverAlpacaManage(); + coverCWebServer(); +} + +#endif \ No newline at end of file diff --git a/src/CoverC/coverVariable.h b/src/CoverC/coverVariable.h new file mode 100644 index 0000000..5b8d3ee --- /dev/null +++ b/src/CoverC/coverVariable.h @@ -0,0 +1,32 @@ +#ifndef COVER_VARIABLE +#define COVER_VARIABLE + +/* BASE */ + +struct coverCStruct{ + unsigned int actualValue; + unsigned int cmdValue; +}; + +coverCStruct coverC; + +/* ALPACA */ + +struct coverCAlpacaParameters{ + unsigned int brightness; +}; + +/* CONFIG*/ + +struct coverCSaveConfigStruct{ + bool execute = false; + bool failed = false; + bool restartNeeded = false; +}; + +struct coverCLoadConfigStruct{ + bool isValid = false; +}; + + +#endif \ No newline at end of file diff --git a/src/CoverC/webserver.h b/src/CoverC/webserver.h new file mode 100644 index 0000000..c357fba --- /dev/null +++ b/src/CoverC/webserver.h @@ -0,0 +1,47 @@ +#ifndef COVERC_SERVER +#define COVERC_SERVER + +void coverCWebServer(){ + + server.on("/coverstatus", HTTP_PUT, [](AsyncWebServerRequest *request) { + AsyncResponseStream *response = request->beginResponseStream("application/json"); + response->printf("\"cover\":{ \"value\":"); + response->print(coverC.actualValue); + response->printf("}}"); + }); + + server.on("/covercmd", HTTP_PUT, [](AsyncWebServerRequest *request) { + int value = -1; + + if (request->hasParam("value")){ + value = request->getParam("value")->value().toInt(); + } else { + request->send(200, "application/json", "{\"error\" : \"Missing Value\"}"); + return; + } + if (value < 0 || value > 8192){ + request->send(200, "application/json", "{\"error\" : \"Out of Range Value\"}"); + return; + } + coverC.cmdValue = value; + request->send(200, "text/html", "{\"done\" : 1}"); + + }); + + AsyncCallbackJsonWebHandler *covercfg = new AsyncCallbackJsonWebHandler("/coverconfig", [](AsyncWebServerRequest * request, JsonVariant & json) { + JsonDocument doc; + doc = json.as(); + if (Config.coverC.pin == doc["pin"]){ + request->send(200, "application/json", "{\"accept\": \"ok\"}"); + } else { + Config.coverC.pin = doc["pin"]; + Config.save.coverC.execute = true; + Config.save.coverC.restartNeeded = true; + request->send(200, "application/json", "{\"reboot\": \"1\"}"); + } + }); + server.addHandler(covercfg); + + server.serveStatic("/ccalibconfig.txt", SPIFFS, "/ccalibconfig.txt"); +} +#endif diff --git a/src/AlpacaDomeServer.h b/src/Dome/alpacaDevices.h similarity index 73% rename from src/AlpacaDomeServer.h rename to src/Dome/alpacaDevices.h index 7cd3a3a..83b725a 100644 --- a/src/AlpacaDomeServer.h +++ b/src/Dome/alpacaDevices.h @@ -1,8 +1,6 @@ #ifndef DOME_FUNC #define DOME_FUNC -#include "domehandler.h" - void domeFalseValueAnswer(AsyncWebServerRequest *request){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); @@ -11,7 +9,7 @@ void domeFalseValueAnswer(AsyncWebServerRequest *request){ response->printf("%sfalse}",Alp_Value); request->send(response); } -void DomeAlpaca(){ +void DomeAlpacaDevices(){ Alpserver.on("/api/v1/dome/0/shutterstatus", HTTP_GET, [](AsyncWebServerRequest *request) { @@ -70,61 +68,6 @@ Alpserver.on("/api/v1/dome/0/connected", request->send(response); }); -Alpserver.on("/api/v1/dome/0/connected", HTTP_PUT, [](AsyncWebServerRequest *request){ - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response,false); - response->printf("}"); - request->send(response); -}); - -Alpserver.on("/api/v1/dome/0/description", HTTP_GET, [](AsyncWebServerRequest *request) { - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->printf("%s\"StefanoTesla Dome\"}",Alp_Value); - request->send(response); -}); - -Alpserver.on("/api/v1/dome/0/driverinfo", HTTP_GET, [](AsyncWebServerRequest *request) { - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->printf("%s\"StefanoTesla Dome response on the fly\"}",Alp_Value); - request->send(response); -}); - -Alpserver.on("/api/v1/dome/0/driverversion", HTTP_GET, [](AsyncWebServerRequest *request) { - - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->printf("%s\"2.0.0\"}",Alp_Value); - request->send(response); - -}); - -Alpserver.on("/api/v1/dome/0/interfaceversion", HTTP_GET, [](AsyncWebServerRequest *request) { - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->printf("%s1}",Alp_Value); - request->send(response); -}); - -Alpserver.on("/api/v1/dome/0/name", HTTP_GET, [](AsyncWebServerRequest *request) { - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->printf("%s\"StefanoTeslaDome\"}",Alp_Value); - request->send(response); -}); Alpserver.on("/api/v1/dome/0/cansetshutter", HTTP_GET, [](AsyncWebServerRequest *request) { GetAlpArguments(request); diff --git a/src/Dome/alpacaManage.h b/src/Dome/alpacaManage.h new file mode 100644 index 0000000..f41de5f --- /dev/null +++ b/src/Dome/alpacaManage.h @@ -0,0 +1,65 @@ +#ifndef DOME_MANAGE +#define DOME_MANAGE + + + +void DomeAlpacaManage(){ + +Alpserver.on("/api/v1/dome/0/connected", HTTP_PUT, [](AsyncWebServerRequest *request){ + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response,false); + response->printf("}"); + request->send(response); +}); + +Alpserver.on("/api/v1/dome/0/description", HTTP_GET, [](AsyncWebServerRequest *request) { + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->printf("%s\"StefanoTesla Dome\"}",Alp_Value); + request->send(response); +}); + +Alpserver.on("/api/v1/dome/0/driverinfo", HTTP_GET, [](AsyncWebServerRequest *request) { + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->printf("%s\"StefanoTesla Dome response on the fly\"}",Alp_Value); + request->send(response); +}); + +Alpserver.on("/api/v1/dome/0/driverversion", HTTP_GET, [](AsyncWebServerRequest *request) { + + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->printf("%s\"2.0.0\"}",Alp_Value); + request->send(response); + +}); + +Alpserver.on("/api/v1/dome/0/interfaceversion", HTTP_GET, [](AsyncWebServerRequest *request) { + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->printf("%s1}",Alp_Value); + request->send(response); +}); + +Alpserver.on("/api/v1/dome/0/name", HTTP_GET, [](AsyncWebServerRequest *request) { + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->printf("%s\"StefanoTeslaDome\"}",Alp_Value); + request->send(response); +}); + +} +#endif \ No newline at end of file diff --git a/src/domehandler.h b/src/Dome/dome.h similarity index 66% rename from src/domehandler.h rename to src/Dome/dome.h index 7fd59e7..6a1c8c4 100644 --- a/src/domehandler.h +++ b/src/Dome/dome.h @@ -1,40 +1,89 @@ #ifndef DOME_HAND #define DOME_HAND + + + unsigned long ShMoveTimeOut; unsigned long ShMoveTimeOutAck; -void domeSetup() { - pinMode(setting.dome.pinStart, OUTPUT); - pinMode(setting.dome.pinHalt, OUTPUT); - pinMode(setting.dome.pinOpen, INPUT); - pinMode(setting.dome.pinClose, INPUT); + +void initDomeConfig(){ + JsonDocument doc; + File file = SPIFFS.open("/domeconfig.txt", FILE_READ); + if (!file) { + Serial.println("Reading Dome config error"); + return; + } + DeserializationError error = deserializeJson(doc, file); + if(error){ + Serial.print(F("deserializeJson() failed: ")); + Serial.println(error.c_str()); + return; + } + Config.dome.pinStart = doc["pinstart"]; + Config.dome.pinHalt = doc["pinhalt"]; + Config.dome.pinOpen = doc["pinopen"]; + Config.dome.pinClose = doc["pinclose"]; + Config.dome.movingTimeOut = doc["tout"]; + Config.dome.enAutoClose = doc["enautoclose"]; + Config.dome.autoCloseTimeOut = doc["autoclose"]; + file.close(); + Config.read.dome.isValid = true; + + pinMode(Config.dome.pinStart, OUTPUT); + pinMode(Config.dome.pinHalt, OUTPUT); + pinMode(Config.dome.pinOpen, INPUT); + pinMode(Config.dome.pinClose, INPUT); } +void saveDomeConfig(){ + String datasetup; + JsonDocument doc; + doc["pinstart"] = Config.dome.pinStart; + doc["pinhalt"] = Config.dome.pinHalt; + doc["pinopen"] = Config.dome.pinOpen; + doc["pinclose"] = Config.dome.pinClose; + doc["tout"] = Config.dome.movingTimeOut; + doc["enautoclose"] = Config.dome.enAutoClose; + doc["autoclose"] = Config.dome.autoCloseTimeOut; + serializeJson(doc, datasetup); + File file = SPIFFS.open("/domeconfig.txt", FILE_WRITE); + file.print(datasetup); + file.close(); +} + + void domeInputState(){ // I used enum for input state for making the cycle code more clean - if (digitalRead(setting.dome.pinClose) == HIGH && digitalRead(setting.dome.pinOpen) == LOW) { + if (digitalRead(Config.dome.pinClose) == HIGH && digitalRead(Config.dome.pinOpen) == LOW) { Dome.ShutterInputState = ShOnlyClose; } - if ( digitalRead(setting.dome.pinClose) == LOW && digitalRead(setting.dome.pinOpen) == HIGH) { + if ( digitalRead(Config.dome.pinClose) == LOW && digitalRead(Config.dome.pinOpen) == HIGH) { Dome.ShutterInputState = ShOnlyOpen; } - if ( digitalRead(setting.dome.pinOpen) == HIGH && digitalRead(setting.dome.pinClose) == HIGH) { + if ( digitalRead(Config.dome.pinOpen) == HIGH && digitalRead(Config.dome.pinClose) == HIGH) { Dome.ShutterInputState = ShInAll; } - if ( digitalRead(setting.dome.pinOpen) == LOW && digitalRead(setting.dome.pinClose) == LOW) { + if ( digitalRead(Config.dome.pinOpen) == LOW && digitalRead(Config.dome.pinClose) == LOW) { Dome.ShutterInputState = ShInNoOne; } } + void LastDomeCommandExe(){ if (Dome.ShutterCommand != Idle) { Dome.LastDomeCommand = Dome.ShutterCommand; } } + +void domeStatusWatcher(){ + +} + void domehandlerloop() { - ShMoveTimeOut = setting.dome.movingTimeOut *1000; + ShMoveTimeOut = Config.dome.movingTimeOut *1000; domeInputState(); LastDomeCommandExe(); // TIMEOUT MOVIMENTAZIONE @@ -44,6 +93,7 @@ void domehandlerloop() { } } + switch (Dome.Cycle) { case 0: @@ -58,7 +108,7 @@ void domehandlerloop() { Dome.ShutterState = ShOpening; Dome.Cycle = 10; } else { - Dome.ShutterState = ShOpen; + Dome.ShutterCommand = Idle; } } @@ -82,14 +132,14 @@ void domehandlerloop() { //Open and close cycle are identical, I just hope to reach the right //Pulse to start to the motor, ack millis for time out and ShMoveTimeOutAck = millis(); - digitalWrite(setting.dome.pinStart, HIGH); + digitalWrite(Config.dome.pinStart, HIGH); Dome.Cycle++; break; case 11: //Take signal end to loose signal if ((millis() - ShMoveTimeOutAck) > 1000) { //Wait 1second anyway if (Dome.ShutterInputState == ShInAll || Dome.ShutterInputState == ShInNoOne) { - digitalWrite(setting.dome.pinStart, LOW); + digitalWrite(Config.dome.pinStart, LOW); ShMoveTimeOutAck = millis(); Dome.Cycle++; } @@ -146,15 +196,15 @@ void domehandlerloop() { //PING PONG - HALT ASPETTO E RIBADISCO LO START case 20:ShMoveTimeOutAck = millis(); - digitalWrite(setting.dome.pinHalt, HIGH); //I need just a pulse for start roof motor - digitalWrite(setting.dome.pinStart, LOW); + digitalWrite(Config.dome.pinHalt, HIGH); //I need just a pulse for start roof motor + digitalWrite(Config.dome.pinStart, LOW); Dome.Cycle++; break; case 21: if ((millis() - ShMoveTimeOutAck) > 1000) { //Wait a second - digitalWrite(setting.dome.pinHalt, LOW); - digitalWrite(setting.dome.pinStart, LOW); + digitalWrite(Config.dome.pinHalt, LOW); + digitalWrite(Config.dome.pinStart, LOW); Dome.Cycle++; ShMoveTimeOutAck = millis(); } @@ -171,15 +221,15 @@ void domehandlerloop() { case 100: //halt command for 1sec ShMoveTimeOutAck = millis(); Dome.ShutterState = ShError; - digitalWrite(setting.dome.pinHalt, HIGH); - digitalWrite(setting.dome.pinStart, LOW); + digitalWrite(Config.dome.pinHalt, HIGH); + digitalWrite(Config.dome.pinStart, LOW); Dome.Cycle++; break; case 101: //halt command for 1sec if ((millis() - ShMoveTimeOutAck) > 1000) { //Setting Output for 1sec - digitalWrite(setting.dome.pinHalt, LOW); - digitalWrite(setting.dome.pinStart, LOW); + digitalWrite(Config.dome.pinHalt, LOW); + digitalWrite(Config.dome.pinStart, LOW); Dome.Cycle++; } break; @@ -200,4 +250,14 @@ void domehandlerloop() { } +#include "webserver.h" +#include "alpacaDevices.h" +#include "alpacaManage.h" + +void domeServer(){ + DomeAlpacaDevices(); + DomeAlpacaManage(); + domeWebServer(); +} + #endif diff --git a/src/Dome/domeVariable.h b/src/Dome/domeVariable.h new file mode 100644 index 0000000..cbab99e --- /dev/null +++ b/src/Dome/domeVariable.h @@ -0,0 +1,68 @@ +#ifndef DOME_VARIABLE +#define DOME_VARIABLE + + +/* BASE AREA */ + +enum ShInEnum { + ShInNoOne, + ShOnlyClose, + ShOnlyOpen, + ShInAll, +}; +enum ShStEnum { + ShOpen, + ShClose, + ShOpening, + ShClosing, + ShError +}; +enum ShCmdEnum { + Idle, + CmdOpen, + CmdClose, + CmdHalt +}; + +struct DomeStruct{ + ShCmdEnum ShutterCommand; + ShStEnum ShutterState; + ShInEnum ShutterInputState; + int Cycle; + bool MoveRetry; + unsigned int LastDomeCommand =0; +}; + +DomeStruct Dome; + +/* ALPACA AREA */ + +struct domeAlpacaStruct{ + ShCmdEnum ShutterCommand; + ShStEnum ShutterState; + ShInEnum ShutterInputState; +}; + +/* CONFIG AREA */ + +struct domeConfig{ + unsigned int pinStart; + unsigned int pinHalt; + unsigned int pinOpen; + unsigned int pinClose; + unsigned int movingTimeOut = 20; + bool enAutoClose; + unsigned int autoCloseTimeOut = 20; +}; + +struct domeSaveConfigStruct{ + bool execute = false; + bool failed = false; + bool restartNeeded = false; +}; + +struct domeLoadConfigStruct{ + bool isValid = false; +}; + +#endif \ No newline at end of file diff --git a/src/Dome/webserver.h b/src/Dome/webserver.h new file mode 100644 index 0000000..3e6415d --- /dev/null +++ b/src/Dome/webserver.h @@ -0,0 +1,82 @@ +#ifndef DOME_SERVER +#define DOME_SERVER + + +void domeWebServer(){ + + + server.on("/domestatus", HTTP_PUT, [](AsyncWebServerRequest *request) { + AsyncResponseStream *response = request->beginResponseStream("application/json"); + response->printf("{\"dome\":{ \"actualState\":"); + response->print(Dome.ShutterState); + response->print(",\"lastCommand\":"); + response->print(Dome.LastDomeCommand); + response->print("}"); + response->print("}"); + }); + + server.on("/domecmd", HTTP_PUT, [](AsyncWebServerRequest *request) { + if (request->hasParam("cmd")){ + int cmd; + cmd = request->getParam("cmd")->value().toInt(); + switch (cmd) { + case 1: + if(Dome.ShutterState != ShOpen){ + Dome.ShutterCommand = CmdOpen; + request->send(200, "application/json", "{\"error\":0}"); + } else { request->send(200, "application/json", "{\"error\":1}"); } + break; + + case 2: + if(Dome.ShutterState != ShClose){ + Dome.ShutterCommand = CmdClose; + request->send(200, "application/json", "{\"error\":0}"); + } else { request->send(200, "application/json", "{\"error\":2}"); } + break; + + case 3: + Dome.ShutterCommand = CmdHalt; + Dome.Cycle = 100; + request->send(200, "application/json", "{\"error\":0}"); + break; + default: + request->send(200, "application/json", "{\"error\":3}"); + break; + } + } else { + request->send(200, "application/json", "{\"error\":3}"); + } + }); + + + AsyncCallbackJsonWebHandler *domecfg = new AsyncCallbackJsonWebHandler("/domeconfig", [](AsyncWebServerRequest * request, JsonVariant & json) { + JsonDocument doc; + doc = json.as(); + bool reboot = false; + if (Config.dome.pinStart != doc["pinstart"]) {reboot=true;} + Config.dome.pinStart = doc["pinstart"]; + if (Config.dome.pinHalt != doc["pinhalt"]) {reboot=true;} + Config.dome.pinHalt = doc["pinhalt"]; + if (Config.dome.pinOpen != doc["pinopen"]) {reboot=true;} + Config.dome.pinOpen = doc["pinopen"]; + if (Config.dome.pinClose != doc["pinclose"]) {reboot=true;} + Config.dome.pinClose = doc["pinclose"]; + + Config.dome.movingTimeOut = doc["tout"]; + Config.dome.enAutoClose = doc["enautoclose"]; + Config.dome.autoCloseTimeOut = doc["autoclose"]; + Config.save.dome.execute = true; + if (reboot){ + Config.save.dome.restartNeeded = true; + request->send(200, "application/json", "{\"reboot\": \"1\"}"); + } else { + request->send(200, "application/json", "{\"accept\": \"ok\"}"); + } + }); + server.addHandler(domecfg); + + + server.serveStatic("/domeconfig.txt", SPIFFS, "/domeconfig.txt"); +} + +#endif \ No newline at end of file diff --git a/src/AlpacaSwitchServer.h b/src/Switches/alpacaDevice.h similarity index 54% rename from src/AlpacaSwitchServer.h rename to src/Switches/alpacaDevice.h index f907610..74f490c 100644 --- a/src/AlpacaSwitchServer.h +++ b/src/Switches/alpacaDevice.h @@ -1,65 +1,7 @@ -#ifndef SWITCH_FUNC -#define SWITCH_FUNC +#ifndef SWITCH_ALPACA_DEVICE +#define SWITCH_ALPACA_DEVICE -#include "switchhandler.h" - -void SwitchAlpaca(){ - - Alpserver.on("/api/v1/switch/0/name", HTTP_GET, [](AsyncWebServerRequest *request) { - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->printf("%s\"StefanoTeslaSwitch\"}",Alp_Value); - request->send(response); - }); - - Alpserver.on("/api/v1/switch/0/connected", HTTP_PUT, [](AsyncWebServerRequest *request){ - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response,false); - response->printf("}"); - request->send(response); - }); - - Alpserver.on("/api/v1/switch/0/description", HTTP_GET, [](AsyncWebServerRequest *request) { - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->printf("%s\"StefanoTesla Switch\"}",Alp_Value); - request->send(response); - }); - - Alpserver.on("/api/v1/switch/0/driverinfo", HTTP_GET, [](AsyncWebServerRequest *request) { - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->printf("%s\"StefanoTesla Dome response on the fly\"}",Alp_Value); - request->send(response); - }); - - Alpserver.on("/api/v1/switch/0/driverversion", HTTP_GET, [](AsyncWebServerRequest *request) { - - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->printf("%s\"2.0.0\"}",Alp_Value); - request->send(response); - - }); - - Alpserver.on("/api/v1/switch/0/interfaceversion", HTTP_GET, [](AsyncWebServerRequest *request) { - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - AlpacaNoErrorSchema(response); - response->printf("%s1}",Alp_Value); - request->send(response); - }); +void SwitchAlpacaDevice(){ Alpserver.on("/api/v1/dome/0/action", HTTP_PUT, [](AsyncWebServerRequest *request) { GetAlpArguments(request); @@ -74,7 +16,7 @@ void SwitchAlpaca(){ AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); AlpacaNoErrorSchema(response); - response->printf("%s%d}",Alp_Value,setting.switches.maxSwitch); + response->printf("%s%d}",Alp_Value,Config.switches.configuredSwitch); request->send(response); }); @@ -92,7 +34,7 @@ void SwitchAlpaca(){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ + if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > Config.switches.configuredSwitch){ response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else { AlpacaNoErrorSchema(response); @@ -105,7 +47,7 @@ void SwitchAlpaca(){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ + if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > Config.switches.configuredSwitch){ response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else { AlpacaNoErrorSchema(response); @@ -118,11 +60,11 @@ void SwitchAlpaca(){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ + if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > Config.switches.configuredSwitch){ response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else { AlpacaNoErrorSchema(response); - response->printf("%s%d}",Alp_Value,Switch[AlpacaData.switches.id].minValue); + response->printf("%s%d}",Alp_Value,Switch[AlpacaData.switches.id].property.minValue); } request->send(response); }); @@ -131,11 +73,11 @@ void SwitchAlpaca(){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ + if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > Config.switches.configuredSwitch){ response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else { AlpacaNoErrorSchema(response); - response->printf("%s%d}",Alp_Value,Switch[AlpacaData.switches.id].maxValue); + response->printf("%s%d}",Alp_Value,Switch[AlpacaData.switches.id].property.maxValue); } request->send(response); }); @@ -144,11 +86,11 @@ void SwitchAlpaca(){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ + if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > Config.switches.configuredSwitch){ response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else { AlpacaNoErrorSchema(response); - response->printf("%s%d}",Alp_Value,Switch[AlpacaData.switches.id].Step); + response->printf("%s%d}",Alp_Value,Switch[AlpacaData.switches.id].property.Step); } request->send(response); }); @@ -157,11 +99,15 @@ void SwitchAlpaca(){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ + if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > Config.switches.configuredSwitch){ response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else { AlpacaNoErrorSchema(response); - response->printf("%s%d}",Alp_Value,Switch[AlpacaData.switches.id].CanSet); + if(Switch[AlpacaData.switches.id].property.type == 1 || Switch[AlpacaData.switches.id].property.type == 3){ + response->printf("%sTrue}",Alp_Value); + } else { + response->printf("%sFalse}",Alp_Value); + } } request->send(response); }); @@ -170,23 +116,12 @@ void SwitchAlpaca(){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ + if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > Config.switches.configuredSwitch){ response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else { AlpacaNoErrorSchema(response); response->printf("%s",Alp_Value); - switch (Switch[AlpacaData.switches.id].type) - { - case 1 ... 2: - response->print(digitalRead(Switch[AlpacaData.switches.id].pin)); - break; - case 3: - response->print(ledcRead(Switch[AlpacaData.switches.id].pwmChannel)); - break; - case 4: - response->print(analogRead(Switch[AlpacaData.switches.id].pin)); - break; - } + response->print(Switch[AlpacaData.switches.id].readValue); response->print(F("}")); } request->send(response); @@ -196,59 +131,20 @@ void SwitchAlpaca(){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ + if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > Config.switches.configuredSwitch){ response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else { AlpacaNoErrorSchema(response); response->printf("%s",Alp_Value); - switch (Switch[AlpacaData.switches.id].type) - { - case 1 ... 2: - digitalRead(Switch[AlpacaData.switches.id].pin) ? response->printf("true") : response->printf("false"); - break; - case 3: - if(ledcRead(Switch[AlpacaData.switches.id].pwmChannel) == 0){ - response->printf("false"); - } else { - response->printf("true"); - } - break; - case 4: - if(analogRead(Switch[AlpacaData.switches.id].pin) == 0){ - response->printf("false"); - } else { - response->printf("true"); - } - break; + if (Switch[AlpacaData.switches.id].readValue == 0){ + response->printf("false"); } - response->print(F("}")); - } - request->send(response); - }); - - Alpserver.on("/api/v1/switch/0/getswitchvalue", HTTP_GET, [](AsyncWebServerRequest *request) { - GetAlpArguments(request); - AsyncResponseStream *response = request->beginResponseStream("application/json"); - AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ - response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); - } else { - AlpacaNoErrorSchema(response); - response->printf("%s",Alp_Value); - switch (Switch[AlpacaData.switches.id].type) - { - case 1 ... 2: - response->print(digitalRead(Switch[AlpacaData.switches.id].pin)); - break; - case 3: - response->print(ledcRead(Switch[AlpacaData.switches.id].pwmChannel)); - break; - case 4: - response->print(analogRead(Switch[AlpacaData.switches.id].pin)); - break; + else { + response->printf("true"); } response->print(F("}")); } + request->send(response); }); @@ -256,23 +152,18 @@ void SwitchAlpaca(){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ + if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > Config.switches.configuredSwitch){ response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else if(!AlpacaData.switches.stateExist || AlpacaData.switches.state < 0 || AlpacaData.switches.state > 1){ response->printf("%s1025,%s\"State value not valid MIN:false MAX:true, %d given\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.state); - } else if( Switch[AlpacaData.switches.id].CanSet == false){ - response->printf("%s1025,%s\"Switch %d cannot be set\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); - } else if( Switch[AlpacaData.switches.id].type == 2 || Switch[AlpacaData.switches.id].type == 4){ + } else if( Switch[AlpacaData.switches.id].property.type == 2 || Switch[AlpacaData.switches.id].property.type == 4){ response->printf("%s1025,%s\"Switch %d is an input, cannot be set\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else { AlpacaNoErrorSchema(response,false); - switch (Switch[AlpacaData.switches.id].type){ - case 1: - digitalWrite(Switch[AlpacaData.switches.id].pin, AlpacaData.switches.state); - break; - case 3: - AlpacaData.switches.state ? ledcWrite(Switch[AlpacaData.switches.id].pwmChannel,Switch[AlpacaData.switches.id].maxValue) : ledcWrite(Switch[AlpacaData.switches.id].pwmChannel,Switch[AlpacaData.switches.id].minValue); - break; + if (AlpacaData.switches.state){ + Switch[AlpacaData.switches.id].cmdValue = Switch[AlpacaData.switches.id].property.maxValue; + } else { + Switch[AlpacaData.switches.id].cmdValue = Switch[AlpacaData.switches.id].property.minValue; } response->printf("}"); } @@ -283,24 +174,15 @@ void SwitchAlpaca(){ GetAlpArguments(request); AsyncResponseStream *response = request->beginResponseStream("application/json"); AlpacaHeaderSchema(response,AlpacaData); - if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > setting.switches.maxSwitch){ + if(!AlpacaData.switches.idExist || AlpacaData.switches.id < 0 || AlpacaData.switches.id > Config.switches.configuredSwitch){ response->printf("%s1025,%s\"The Switch %d doesn't exist\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); - } else if(!AlpacaData.switches.intValueExist || AlpacaData.switches.intValue < Switch[AlpacaData.switches.id].minValue || AlpacaData.switches.intValue > Switch[AlpacaData.switches.id].maxValue){ - response->printf("%s1025,%s\"State value not valid MIN:%d MAX:%d, %d given\"}",Alp_ErrN,Alp_ErrM,Switch[AlpacaData.switches.id].minValue,Switch[AlpacaData.switches.id].maxValue,AlpacaData.switches.intValue); - } else if( Switch[AlpacaData.switches.id].CanSet == false){ - response->printf("%s1025,%s\"Switch %d cannot be set\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); - } else if( Switch[AlpacaData.switches.id].type == 2 || Switch[AlpacaData.switches.id].type == 4){ + } else if(!AlpacaData.switches.intValueExist || !validateSwitchValue(AlpacaData.switches.id,AlpacaData.switches.intValue)){ + response->printf("%s1025,%s\"State value not valid MIN:%d MAX:%d, %d given\"}",Alp_ErrN,Alp_ErrM,Switch[AlpacaData.switches.id].property.minValue,Switch[AlpacaData.switches.id].property.maxValue,AlpacaData.switches.intValue); + } else if( Switch[AlpacaData.switches.id].property.type == 2 || Switch[AlpacaData.switches.id].property.type == 4){ response->printf("%s1025,%s\"Switch %d is an input, cannot be set\"}",Alp_ErrN,Alp_ErrM,AlpacaData.switches.id); } else { AlpacaNoErrorSchema(response,false); - switch (Switch[AlpacaData.switches.id].type){ - case 1: - digitalWrite(Switch[AlpacaData.switches.id].pin, AlpacaData.switches.intValue); - break; - case 3: - ledcWrite(Switch[AlpacaData.switches.id].pwmChannel,AlpacaData.switches.intValue); - break; - } + Switch[AlpacaData.switches.id].cmdValue = AlpacaData.switches.intValue; response->printf("}"); } request->send(response); diff --git a/src/Switches/alpacaManage.h b/src/Switches/alpacaManage.h new file mode 100644 index 0000000..ad50f6a --- /dev/null +++ b/src/Switches/alpacaManage.h @@ -0,0 +1,64 @@ +#ifndef SWITCH_ALPACA_MANAGE +#define SWITCH_ALPACA_MANAGE + +void SwitchAlpacaManage(){ + + Alpserver.on("/api/v1/switch/0/name", HTTP_GET, [](AsyncWebServerRequest *request) { + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->printf("%s\"StefanoTeslaSwitch\"}",Alp_Value); + request->send(response); + }); + + Alpserver.on("/api/v1/switch/0/connected", HTTP_PUT, [](AsyncWebServerRequest *request){ + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response,false); + response->printf("}"); + request->send(response); + }); + + Alpserver.on("/api/v1/switch/0/description", HTTP_GET, [](AsyncWebServerRequest *request) { + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->printf("%s\"StefanoTesla Switch\"}",Alp_Value); + request->send(response); + }); + + Alpserver.on("/api/v1/switch/0/driverinfo", HTTP_GET, [](AsyncWebServerRequest *request) { + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->printf("%s\"StefanoTesla Dome response on the fly\"}",Alp_Value); + request->send(response); + }); + + Alpserver.on("/api/v1/switch/0/driverversion", HTTP_GET, [](AsyncWebServerRequest *request) { + + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->printf("%s\"2.0.0\"}",Alp_Value); + request->send(response); + + }); + + Alpserver.on("/api/v1/switch/0/interfaceversion", HTTP_GET, [](AsyncWebServerRequest *request) { + GetAlpArguments(request); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + AlpacaHeaderSchema(response,AlpacaData); + AlpacaNoErrorSchema(response); + response->printf("%s1}",Alp_Value); + request->send(response); + }); + +} + +#endif diff --git a/src/Switches/switch.h b/src/Switches/switch.h new file mode 100644 index 0000000..4ee5288 --- /dev/null +++ b/src/Switches/switch.h @@ -0,0 +1,178 @@ +#ifndef SWITCH_HAND +#define SWITCH_HAND + +bool validateSwitchValue(int id,int value){ + + if(value >= Switch[id].property.minValue && value <= Switch[id].property.minValue){ + return true; + } + + return false; +} + +void switchSetup() { + int i=0; +/* Switch Setup */ + +/* Default Switch setting + + pin -> Choose the GPIO where switch is plugged on! + minValue -> Min Value the switch can have (default is 0 and is set to 0 if Switch is Output) + maxValue -> Max Value the switch can have (default is 1 and is forced to 1 if Switch is Output) + Step -> Choose the step for change the value of Switch (default 1 and forced to 1 if is output) + pwmChannel -> Default -1, the value can be 0..15 according to esp32 pwm channels + +Please refer to this page to understand wich output/input you can use without problems: +https://randomnerdtutorials.com/esp32-pinout-reference-gpios/ +*/ + + +/* automatic setup for Switch */ + + for (i=0;i<_MAX_SWITCH_ID_;i++){ + if(Switch[i].pin == 0){ + Switch[i].Name =""; + Switch[i].Description =""; + return; + } + switch(Switch[i].property.type){ + case 1: //Digital Output + pinMode(Switch[i].pin, OUTPUT); + break; + case 2: //Digital Input + pinMode(Switch[i].pin, INPUT); + break; + case 3: //PWM Output + ledcSetup(pwmchannles, 5000, 13); + ledcAttachPin(Switch[i].pin, pwmchannles); + Switch[i].pwmChannel = pwmchannles; + Switch[i].property.minValue = 0; + Switch[i].property.maxValue = 8192; + pwmchannles++; + break; + case 4: //Analog Input + Switch[i].property.minValue = 0; + Switch[i].property.maxValue = 4095; + break; + default: + Serial.print(F("Wrong type ")); + Serial.print(Switch[i].property.type); + Serial.print(F(" for pin ")); + Serial.print(Switch[i].pin); + } + } +} + +void initSwitchConfig(){ + + JsonDocument doc; + File file = SPIFFS.open("/switchconfig.txt", FILE_READ); + if (!file) { + Serial.println(F("Reading Switch config error")); + return; + } + + DeserializationError error = deserializeJson(doc, file); + if(error){ + Serial.print(F("deserialize switch setting failed: ")); + Serial.println(error.c_str()); + return; + } + + int i=0; + int type = 0; + int pin = 0; + for (JsonObject elem : doc.as()) { + pin = elem["pin"].as(); + type = elem["type"].as(); + if (validatePin(pin,type)){ + Switch[i].Name = elem["name"].as(); + Switch[i].Description = elem["desc"].as(); + Switch[i].pin = pin; + Switch[i].property.type = type; + Config.switches.configuredSwitch = i; + i++; + } else{ + break; + } + } + file.close(); + Config.read.switches.isValid = true; + switchSetup(); +} + +void saveSwitchConfig(){ + int i = 0; + File file = SPIFFS.open("/switchconfig.txt", FILE_WRITE); + file.print("["); + for(i=0;i<_MAX_SWITCH_ID_;i++){ + file.print("{\"name\":\""); + file.print(Switch[i].Name.substring(0,32)); + file.print("\",\"desc\":\""); + file.print(Switch[i].Description.substring(0,32)); + file.print("\",\"type\":"); + file.print(Switch[i].property.type); + file.print(",\"pin\":"); + file.print(Switch[i].pin); + file.print("}"); + if(i != _MAX_SWITCH_ID_ - 1){ + file.print(","); + } + } + file.print("]"); + file.close(); +} + + +void switchLoop(){ + + for(int i=0;ihasParam("id")){ + id = request->getParam("id")->value().toInt(); + } else { + request->send(200, "application/json", "{\"error\" : \"Missing ID\"}"); + return; + } + if (request->hasParam("value")){ + value = request->getParam("value")->value().toInt(); + } else { + request->send(200, "application/json", "{\"error\" : \"Missing Value\"}"); + return; + } + if (id < 1 || id >= Config.switches.configuredSwitch){ + request->send(200, "application/json", "{\"error\" : \"ID Out of Range\"}"); return; + } + if (Switch[id].property.type != 1 || Switch[id].property.type != 3){ + request->send(200, "application/json", "{\"error\" : \"Switch cannot be setted\"}"); + return; + } + if (value < Switch[id].property.minValue || value > Switch[id].property.maxValue){ + request->send(200, "application/json", "{\"error\" : \"Value outside limits\"}"); + return; + } + + Switch[id].cmdValue = value; + request->send(200, "text/html", "{\"done\" : 1}"); + + }); + + + server.on("/switch/status", HTTP_GET, [](AsyncWebServerRequest *request) { + int i; + AsyncResponseStream *response = request->beginResponseStream("application/json"); + response->printf("{"); + response->print("\"switches\": ["); + for (i=0;iprint("{\"id\":"); + response->print(i); + response->print(",\"name\":\""); + response->print(Switch[i].Name); + response->print("\",\"description\":\""); + response->print(Switch[i].Description); + response->print(",\"actualValue\":"); + response->print(Switch[i].readValue); + response->print(",\"min\":"); + response->print(Switch[i].property.minValue); + response->print(",\"max\":"); + response->print(Switch[i].property.maxValue); + response->print(",\"step\":"); + response->print(Switch[i].property.Step); + response->print("}"); + if(i != Config.switches.configuredSwitch - 1 ){ + response->printf(","); + } + } + response->printf("]}"); + request->send(response); + }); + + + AsyncCallbackJsonWebHandler *switchConfig = new AsyncCallbackJsonWebHandler("/switchconfig", [](AsyncWebServerRequest * request, JsonVariant & json) { + JsonDocument doc; + int i=0; + int x=0; + int type = 0; + int pin = 0; + bool err = false; + bool reboot = false; + for (JsonObject elem : json.as()) { + type = elem["type"].as(); + pin = elem["pin"].as(); + if((type > 0 && type <= 4) && pin < 40 && validatePin(pin,type)){ + if(pin != Switch[i].pin || type != Switch[i].property.type) { reboot = true; } + Switch[i].pin = pin; + Switch[i].property.type = type; + Switch[i].Name = elem["name"].as(); + Switch[i].Description = elem["desc"].as(); + } else { + err = true; + continue; + } + i++; + } + if(err){ + request->send(200, "application/json", "{\"error\": \"some type or input are wrong\"}"); + return; + } + for(x=i;x<_MAX_SWITCH_ID_;x++){ + Switch[x].Name = ""; + Switch[x].Description = ""; + Switch[x].pin = 0; + Switch[x].property.type = 0; + Switch[x].property.minValue = 0; + Switch[x].property.maxValue = 1; + } + Config.save.switches.execute = true; + if (reboot){ + Config.save.switches.restartNeeded = true; + request->send(200, "application/json", "{\"reboot\": \"1\"}"); + } else { + request->send(200, "application/json", "{\"accept\": \"ok\"}"); + } + + }); + server.addHandler(switchConfig); + + server.on("/switch/getconfig", HTTP_GET, [](AsyncWebServerRequest *request) { + int i; + AsyncResponseStream *response = request->beginResponseStream("application/json"); + response->print("{"); + response->print("\"switches\":["); + for(i=0;iprint("{\"name\":\""); + response->print(Switch[i].Name); + response->print("\",\"desc\":\""); + response->print(Switch[i].Description); + response->print("\",\"type\":"); + response->print(Switch[i].property.type); + response->print(",\"pin\":"); + response->print(Switch[i].pin); + response->print("}"); + if (i != Config.switches.configuredSwitch - 1 ){ + response->print(","); + } + } + response->print("]"); + + response->print("}"); + request->send(response); + }); + + server.serveStatic("/switchconfig.txt", SPIFFS, "/switchconfig.txt"); +} +#endif \ No newline at end of file diff --git a/src/browserServer.h b/src/browserServer.h index 1bc0beb..76671a1 100644 --- a/src/browserServer.h +++ b/src/browserServer.h @@ -22,325 +22,91 @@ void browserServer(){ request->send(SPIFFS, "/setup.txt", "text/plain"); }); - server.on("/domecmd", HTTP_PUT, [](AsyncWebServerRequest *request) { - if (request->hasParam("cmd")){ - int cmd; - cmd = request->getParam("cmd")->value().toInt(); - switch (cmd) { - case 1: - if(Dome.ShutterState != ShOpen){ - Dome.ShutterCommand = CmdOpen; - request->send(200, "application/json", "{\"error\":0}"); - } else { request->send(200, "application/json", "{\"error\":1}"); } - break; - - case 2: - if(Dome.ShutterState != ShClose){ - Dome.ShutterCommand = CmdClose; - request->send(200, "application/json", "{\"error\":0}"); - } else { request->send(200, "application/json", "{\"error\":2}"); } - break; - - case 3: - Dome.ShutterCommand = CmdHalt; - Dome.Cycle = 100; - request->send(200, "application/json", "{\"error\":0}"); - break; - default: - request->send(200, "application/json", "{\"error\":3}"); - break; - } - } else { - request->send(200, "application/json", "{\"error\":3}"); - } - }); - - server.on("/switchcmd", HTTP_PUT, [](AsyncWebServerRequest *request) { - int id = -1; - int value = -1; - if (request->hasParam("id")){ - id = request->getParam("id")->value().toInt(); - } else { - request->send(200, "application/json", "{\"error\" : \"Missing ID\"}"); - return; - } - if (request->hasParam("value")){ - value = request->getParam("value")->value().toInt(); - } else { - request->send(200, "application/json", "{\"error\" : \"Missing Value\"}"); - return; - } - if (id >= setting.switches.maxSwitch){ - request->send(200, "application/json", "{\"error\" : \"ID Out of Range\"}"); return; - } - if (!Switch[id].CanSet){ - request->send(200, "application/json", "{\"error\" : \"Switch cannot be setted\"}"); - return; - } - if (value < Switch[id].minValue || value > Switch[id].maxValue){ - request->send(200, "application/json", "{\"error\" : \"Value outside limits\"}"); - return; - } - - switch (Switch[id].type) - { - case 1: - value == 1 ? digitalWrite(Switch[id].pin, HIGH) : digitalWrite(Switch[id].pin, LOW); - break; - - case 3: - ledcWrite(Switch[id].pwmChannel,value); - break; - default: - break; - } - request->send(200, "text/html", "{\"done\" : 1}"); - - }); - - server.on("/covercmd", HTTP_PUT, [](AsyncWebServerRequest *request) { - int value = -1; - - if (request->hasParam("value")){ - value = request->getParam("value")->value().toInt(); - } else { - request->send(200, "application/json", "{\"error\" : \"Missing Value\"}"); - return; - } - if (value < 0 || value > 8192){ - request->send(200, "application/json", "{\"error\" : \"Out of Range Value\"}"); - return; - } - ledcWrite(0 ,value); - request->send(200, "text/html", "{\"done\" : 1}"); - - }); - server.on("/status", HTTP_GET, [](AsyncWebServerRequest *request) { int i; AsyncResponseStream *response = request->beginResponseStream("application/json"); - - response->printf("{\"dome\":{ \"actualState\":"); + response->printf("{"); + #ifdef DOME + response->printf("\"dome\":{ \"actualState\":"); response->print(Dome.ShutterState); response->print(",\"lastCommand\":"); response->print(Dome.LastDomeCommand); response->print("},"); + #endif + + #ifdef COVERC response->printf("\"cover\":{ \"value\":"); - response->print(ledcRead(0)); + response->print(coverC.actualValue); response->print("},"); - response->print("\"switches\": ["); - for (i=0;iprint("{\"id\":"); - response->print(i); - response->print(",\"name\":\""); - response->print(Switch[i].Name); - response->print("\",\"description\":\""); - response->print(Switch[i].Description); - response->print("\",\"canBeHandle\":"); - response->print(Switch[i].CanSet); - response->print(",\"type\":"); - response->print(Switch[i].analog); - response->print(",\"actualValue\":"); - switch (Switch[i].type) - { - case 1: - case 2: - response->print(digitalRead(Switch[i].pin)); - break; - case 3: - response->print(ledcRead(Switch[i].pwmChannel)); - break; - case 4: - response->print(analogRead(Switch[i].pin)); - break; - default: - break; - } - response->print(",\"min\":"); - response->print(Switch[i].minValue); - response->print(",\"max\":"); - response->print(Switch[i].maxValue); - response->print(",\"step\":"); - response->print(Switch[i].Step); - response->print("}"); - if(i != setting.switches.maxSwitch - 1 ){ - response->printf(","); - } - } - response->printf("],\"freeHeap\":"); + #endif + response->printf("\"freeHeap\":"); response->print(ESP.getFreeHeap()); response->printf(",\"minFreeHeap\":"); response->print(ESP.getMinFreeHeap()); response->printf(",\"totalHeap\":"); response->print(ESP.getHeapSize()); response->printf(",\"upTime\":"); - response->print(upTimeESP32); + response->print(Global.esp32.upTime.minutes); response->printf(",\"upWiFiTime\":"); - response->print(upTimeWiFi); + response->print(Global.wifi.upTime.minutes); response->print("}"); request->send(response); }); - AsyncCallbackJsonWebHandler *domecfg = new AsyncCallbackJsonWebHandler("/domeconfig", [](AsyncWebServerRequest * request, JsonVariant & json) { - JsonDocument doc; - doc = json.as(); - setting.dome.pinStart = doc["pinstart"]; - setting.dome.pinHalt = doc["pinhalt"]; - setting.dome.pinOpen = doc["pinopen"]; - setting.dome.pinClose = doc["pinclose"]; - setting.dome.movingTimeOut = doc["tout"]; - setting.dome.enAutoClose = doc["enautoclose"]; - setting.dome.autoCloseTimeOut = doc["autoclose"]; - FileHandler.saveDomeSetting = true; - request->send(200, "application/json", "{\"accept\": \"ok\"}"); - }); - server.addHandler(domecfg); - - - AsyncCallbackJsonWebHandler *switchConfig = new AsyncCallbackJsonWebHandler("/switchconfig", [](AsyncWebServerRequest * request, JsonVariant & json) { - JsonDocument doc; - int i=0; - int x=0; - int type = 0; - int pin = 0; - bool err = false; - bool reboot = false; - for (JsonObject elem : json.as()) { - type = elem["type"].as(); - pin = elem["pin"].as(); - if(type != 0 && pin != 0){ - switch(type){ - - case 1: //Digital Output - if(Switch[i].CanSet != true){ reboot = true; } - if(Switch[i].pin != pin){ reboot = true; } - Switch[i].CanSet = true; - Switch[i].analog = false; - Switch[i].pin = pin; - Switch[i].minValue = 0; - Switch[i].maxValue = 1; - break; - - case 2: //Digital Input - if(Switch[i].CanSet != false){ reboot = true; } - if(Switch[i].pin != pin){ reboot = true; } - Switch[i].CanSet = false; - Switch[i].analog = false; - Switch[i].pin = pin; - Switch[i].minValue = 0; - Switch[i].maxValue = 1; - break; - case 3: //PWM Output - if(Switch[i].CanSet != true){ reboot = true; } - if(Switch[i].pin != pin){ reboot = true; } - Switch[i].CanSet = true; - Switch[i].analog = true; - Switch[i].pin = pin; - break; - - case 4: //Analog Input - if(Switch[i].CanSet != false){ reboot = true; } - if(Switch[i].pin != pin){ reboot = true; } - Switch[i].CanSet = false; - Switch[i].analog = true; - Switch[i].pin = pin; - break; - - default: - Serial.println("/switchconfig wrong pin type"); - err = true; - break; - } - Switch[i].type = type; - Switch[i].Name = elem["name"].as(); - Switch[i].Description = elem["desc"].as(); - } else { - err = true; - continue; - } - i++; - } - if(err){ - request->send(200, "application/json", "{\"error\": \"some type or input are wrong\"}"); - return; - } - for(x=i;x<_MAX_SWITCH_ID_;x++){ - Switch[x].Name = ""; - Switch[x].Description = ""; - Switch[x].pin = 0; - Switch[x].type = 0; - Switch[x].minValue = 0; - Switch[x].maxValue = 1; - } - if (reboot){ - FileHandler.restartNeeded = true; - FileHandler.saveSwitchSetting = true; - request->send(200, "application/json", "{\"reboot\": \"1\"}"); - } else { - FileHandler.saveSwitchSetting = true; - request->send(200, "application/json", "{\"accept\": \"ok\"}"); - } - - }); - server.addHandler(switchConfig); - - AsyncCallbackJsonWebHandler *covercfg = new AsyncCallbackJsonWebHandler("/coverconfig", [](AsyncWebServerRequest * request, JsonVariant & json) { - JsonDocument doc; - doc = json.as(); - if (setting.coverCalibration.pin == doc["pin"]){ - request->send(200, "application/json", "{\"accept\": \"ok\"}"); - } else { - setting.coverCalibration.pin = doc["pin"]; - FileHandler.saveCoverCalibratorSetting = true; - FileHandler.restartNeeded = true; - request->send(200, "application/json", "{\"reboot\": \"1\"}"); - } - }); - server.addHandler(covercfg); - server.on("/config", HTTP_GET, [](AsyncWebServerRequest *request) { int i; AsyncResponseStream *response = request->beginResponseStream("application/json"); - response->print("{\"dome\":{ \"pinstart\":"); - response->print(setting.dome.pinStart); + response->print("{"); + #ifdef DOME + response->print("\"dome\":{ \"pinstart\":"); + response->print(Config.dome.pinStart); response->print(",\"pinhalt\":"); - response->print(setting.dome.pinHalt); + response->print(Config.dome.pinHalt); response->print(",\"pinopen\":"); - response->print(setting.dome.pinOpen); + response->print(Config.dome.pinOpen); response->print(",\"pinclose\":"); - response->print(setting.dome.pinClose); + response->print(Config.dome.pinClose); response->print(",\"tout\":"); - response->print(setting.dome.movingTimeOut); + response->print(Config.dome.movingTimeOut); response->print(",\"enautoclose\":"); - setting.dome.enAutoClose ? response->print("true") : response->print("false"); + Config.dome.enAutoClose ? response->print("true") : response->print("false"); response->print(",\"autoclose\":"); - response->print(setting.dome.autoCloseTimeOut); - response->print("},"); + response->print(Config.dome.autoCloseTimeOut); + response->print("}"); + #endif + #ifdef COVERC + response->print(","); response->print("\"cover\":{ \"pin\":"); - response->print(setting.coverCalibration.pin); - response->print("},"); + response->print(Config.coverC.pin); + response->print("}"); + #endif + #ifdef SWITCH + response->print(","); response->print("\"switches\":["); - for(i=0;iprint("{\"name\":\""); response->print(Switch[i].Name); response->print("\",\"desc\":\""); response->print(Switch[i].Description); response->print("\",\"type\":"); - response->print(Switch[i].type); + response->print(Switch[i].property.type); response->print(",\"pin\":"); response->print(Switch[i].pin); response->print("}"); - if (i != setting.switches.maxSwitch - 1 ){ + if (i != Config.switches.configuredSwitch - 1 ){ response->print(","); } } - response->print("]}"); + response->print("]"); + #endif + response->print("}"); request->send(response); }); - server.serveStatic("/domeconfig.txt", SPIFFS, "/domeconfig.txt"); - server.serveStatic("/switchconfig.txt", SPIFFS, "/switchconfig.txt"); - server.serveStatic("/ccalibconfig.txt", SPIFFS, "/ccalibconfig.txt"); + + #ifdef COVERC + + #endif server.serveStatic("/favicon.ico", SPIFFS, "/favicon.ico").setCacheControl("max-age=31536000"); server.serveStatic("/assets/", SPIFFS, "/assets/").setCacheControl("max-age=31536000"); diff --git a/src/configuration.h b/src/configuration.h new file mode 100644 index 0000000..22cd431 --- /dev/null +++ b/src/configuration.h @@ -0,0 +1,35 @@ +#ifndef CONFIGURATION +#define CONFIGURATION + + +void saveConfig(){ + + #ifdef DOME + if(Config.save.dome.execute){ + saveDomeConfig(); + } + #endif + + #ifdef SWITCH + if(Config.save.switches.execute){ + saveSwitchConfig(); + } + #endif + + #ifdef COVERC + if(Config.save.coverC.execute){ + saveCoverCConfig(); + } + #endif + + Config.save.dome.execute = false; + Config.save.switches.execute = false; + Config.save.coverC.execute = false; + + if(Config.save.coverC.restartNeeded || Config.save.dome.restartNeeded || Config.save.switches.restartNeeded){ + ESP.restart(); + } + +} + +#endif \ No newline at end of file diff --git a/src/dome.cpp b/src/dome.cpp deleted file mode 100644 index ac5c88a..0000000 --- a/src/dome.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include -#include "AsyncJson.h" -#include "AsyncUDP.h" -#include "HTTPClient.h" -#include -#include -#include -#include "SPIFFS.h" -#include "header.h" -#include - -AsyncWebServer server(80); -AsyncWebServer Alpserver(4567); - -unsigned long previousWifiMillis = 0; -unsigned long previousUpTimeWifi = 0; -unsigned long previousUpTimeESP32 = 0; -unsigned long upTimeInterval = 60000; -unsigned long wifiInterval = 30000; -unsigned long upTimeWiFi = 0; -unsigned long upTimeESP32 = 0; - -#include "AlpacaManageFunction.h" -#include "AlpacaDomeServer.h" -#include "AlpacaSwitchServer.h" -#include "AlpacaCoverCalibratorServer.h" -#include "browserServer.h" -#include "fileHandler.h" -DNSServer dns; -///////enter your sensitive data in the Secret tab/arduino_secrets.h - -unsigned const int localPort = 32227; //The Alpaca Discovery test port -unsigned const int alpacaPort = 4567; //The (fake) port that the Alpaca API would be available on - - -AsyncUDP udp; - - - -void ServerNotFound(AsyncWebServerRequest *request) { - request->send(404, "text/plain", "Not found"); - Serial.println("404"); - Serial.println(request->url()); -} - -void setup() -{ - Serial.begin(115200); - AlpacaData.serverTransactionID = 0; -/* reading configuration from file */ - if (!SPIFFS.begin()) { Serial.println("An Error has occurred while mounting SPIFFS"); return; } - readDomeConfig(); - domeSetup(); - readCoverCalibConfig(); - CoverCalibratorSetup(); - readSwitchConfig(); - switchSetup(); - - Serial.println("Listening for discovery requests..."); - AsyncWiFiManager wifiManager(&server,&dns); - wifiManager.autoConnect("TeslaBoard"); - Serial.print("Connect with IP Address: "); - Serial.println(WiFi.localIP()); - - - if (udp.listen(32227)) - { - Serial.println("Listening for discovery requests..."); - udp.onPacket([](AsyncUDPPacket packet) { - if (packet.length() < 16) - { - return; - } - //Compare packet to Alpaca Discovery string - if (strncmp("alpacadiscovery1", (char *)packet.data(), 16) != 0) - { - return; - } - packet.printf("{\"alpacaport\": %d}", alpacaPort); - }); - } - - Alpserver.onNotFound(notFound); - /*** MANAGE AREA ***/ - - - AlpacaManager(); - DomeAlpaca(); - SwitchAlpaca(); - CoverCalibratorServer(); - browserServer(); - - /** END SWITCH SPECIFIC METHODS **/ - Alpserver.begin(); - AsyncElegantOTA.begin(&server); // Start ElegantOTA - server.begin(); -} - -void loop() -{ - fileLoop(); - domehandlerloop(); - - - unsigned long currentMillis = millis(); - if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousWifiMillis >=wifiInterval)) { - WiFi.disconnect(); - WiFi.reconnect(); - previousWifiMillis = currentMillis; - upTimeWiFi = 0; - } - - - - //one minute clock - if (currentMillis - previousUpTimeESP32 > upTimeInterval){ - upTimeESP32 +=1; - if(WiFi.status() == WL_CONNECTED ){ - upTimeWiFi +=1; - } - previousUpTimeESP32 = currentMillis; - } - -} diff --git a/src/fileHandler.h b/src/fileHandler.h deleted file mode 100644 index b2d925f..0000000 --- a/src/fileHandler.h +++ /dev/null @@ -1,180 +0,0 @@ -#ifndef FILE_HAND -#define FILE_HAND - -void readDomeConfig(){ - JsonDocument doc; - File file = SPIFFS.open("/domeconfig.txt", FILE_READ); - if (!file) { - Serial.println("Reading Dome config error"); - return; - } - DeserializationError error = deserializeJson(doc, file); - - if(error){ - Serial.print(F("deserializeJson() failed: ")); - Serial.println(error.c_str()); - } else { - setting.dome.pinStart = doc["pinstart"]; - setting.dome.pinHalt = doc["pinhalt"]; - setting.dome.pinOpen = doc["pinopen"]; - setting.dome.pinClose = doc["pinclose"]; - setting.dome.movingTimeOut = doc["tout"]; - setting.dome.enAutoClose = doc["enautoclose"]; - setting.dome.autoCloseTimeOut = doc["autoclose"]; - } - file.close(); -} - - -void saveDomeConfig(){ - String datasetup; - JsonDocument doc; - doc["pinstart"] = setting.dome.pinStart; - doc["pinhalt"] = setting.dome.pinHalt; - doc["pinopen"] = setting.dome.pinOpen; - doc["pinclose"] = setting.dome.pinClose; - doc["tout"] = setting.dome.movingTimeOut; - doc["enautoclose"] = setting.dome.enAutoClose; - doc["autoclose"] = setting.dome.autoCloseTimeOut; - serializeJson(doc, datasetup); - File file = SPIFFS.open("/domeconfig.txt", FILE_WRITE); - file.print(datasetup); - file.close(); -} - -void readCoverCalibConfig(){ - JsonDocument doc; - File file = SPIFFS.open("/ccalibconfig.txt", FILE_READ); - if (!file) { - Serial.println("Reading Cover Calibrator config error"); - return; - } - DeserializationError error = deserializeJson(doc, file); - - if(error){ - Serial.print(F("deserializeJson() failed: ")); - Serial.println(error.c_str()); - } else { - setting.coverCalibration.pin = doc["pin"]; - } - file.close(); -} - -void saveCoverCalibConfig(){ - String datasetup; - JsonDocument doc; - doc["pin"] = setting.coverCalibration.pin; - serializeJson(doc, datasetup); - File file = SPIFFS.open("/ccalibconfig.txt", FILE_WRITE); - file.print(datasetup); - file.close(); -} - -void readSwitchConfig(){ - JsonDocument doc; - File file = SPIFFS.open("/switchconfig.txt", FILE_READ); - if (!file) { - Serial.println(F("Reading Switch config error")); - return; - } - DeserializationError error = deserializeJson(doc, file); - - if(error){ - Serial.print(F("deserialize switch setting failed: ")); - Serial.println(error.c_str()); - } - - int i=0; - int type = 0; - int pin = 0; - for (JsonObject elem : doc.as()) { - type = elem["type"].as(); - pin = elem["pin"].as(); - if(type != 0 && (pin != 0 || pin != 99)){ - Switch[i].Name = elem["name"].as(); - Switch[i].Description = elem["desc"].as(); - Switch[i].type = type; - Switch[i].CanSet = false; - Switch[i].analog = false; - Switch[i].pin = pin; - Switch[i].minValue = 0; - Switch[i].maxValue = 1; - switch(type){ - case 1: //Digital Output - Switch[i].CanSet = true; - Switch[i].pin = pin; - - break; - case 2: //Digital Input - Switch[i].pin = pin; - break; - case 3: //PWM Output - Switch[i].CanSet = true; - Switch[i].analog = true; - Switch[i].pin = pin; - break; - case 4: //Analog Input - Switch[i].CanSet = false; - Switch[i].analog = true; - Switch[i].pin = pin; - break; - - default: - break; - } - } else { - setting.switches.maxSwitch = i; - break; - } - i++; - } - doc.clear(); - file.close(); -} - -void saveSwitchConfig(){ - int i = 0; - File file = SPIFFS.open("/switchconfig.txt", FILE_WRITE); - file.print("["); - for(i=0;i<_MAX_SWITCH_ID_;i++){ - file.print("{\"name\":\""); - file.print(Switch[i].Name.substring(0,32)); - file.print("\",\"desc\":\""); - file.print(Switch[i].Description.substring(0,32)); - file.print("\",\"type\":"); - file.print(Switch[i].type); - file.print(",\"pin\":"); - file.print(Switch[i].pin); - file.print("}"); - if(i != _MAX_SWITCH_ID_ - 1){ - file.print(","); - } - } - file.print("]"); - file.close(); -} - -void fileLoop(){ - - if(FileHandler.saveDomeSetting){ - FileHandler.saveDomeSetting = false; - saveDomeConfig(); - Serial.println("richiesta salvataggio dati dome"); - if(FileHandler.restartNeeded){ESP.restart();} - } - - if(FileHandler.saveSwitchSetting){ - FileHandler.saveSwitchSetting = false; - saveSwitchConfig(); - Serial.println("richiesta salvataggio dati switch"); - if(FileHandler.restartNeeded){ESP.restart();} - } - - if(FileHandler.saveCoverCalibratorSetting){ - FileHandler.saveCoverCalibratorSetting = false; - saveCoverCalibConfig(); - Serial.println("richiesta salvataggio CoverCalibrator"); - if(FileHandler.restartNeeded){ESP.restart();} - } -} -#endif \ No newline at end of file diff --git a/src/header.h b/src/header.h index 8ee3566..01b591c 100644 --- a/src/header.h +++ b/src/header.h @@ -1,126 +1,126 @@ -struct FileStruct{ - bool saveSwitchSetting = false; - bool saveDomeSetting = false; - bool saveCoverCalibratorSetting = false; - bool restartNeeded = false; -}; - -FileStruct FileHandler; - -typedef struct{ - bool idExist; - int id; /* used for switch ID */ - bool stateExist; - bool state; /* used for setswitch */ - bool intValueExist; - int intValue; /* used for setswitchvalue */ - bool nameExist; - String name; /* used for set switch name */ -} switchAlpacaParameters; +unsigned int pwmchannles = 1;//channel 0 is reserved to coverCalibrator -typedef struct{ - unsigned int brightness; -} coverCalibratorAlpacaParameters; +/* ALPACA DATA */ - -/* ALPACA COMMON DATA */ struct AlpacaCommonData{ uint32_t clientTransactionID; uint32_t serverTransactionID = 0; uint32_t clientID; + unsigned long LastServerRequest; bool boConnect; + //domeAlpacaParameters dome; switchAlpacaParameters switches; - coverCalibratorAlpacaParameters coverCalibrator; + coverCAlpacaParameters coverC; }; AlpacaCommonData AlpacaData; -/*END ALPACA COMMON DATA */ +/*END ALPACA DATA */ + + +/** CONFIG STRUCT **/ + +struct saveConfigStruct{ + domeSaveConfigStruct dome; + switchSaveConfigStruct switches; + coverCSaveConfigStruct coverC; -/**DOME DATA**/ -enum ShInEnum { - ShInNoOne, - ShOnlyClose, - ShOnlyOpen, - ShInAll, }; -enum ShStEnum { - ShOpen, - ShClose, - ShOpening, - ShClosing, - ShError + +struct validConfig{ + domeLoadConfigStruct dome ; + switchLoadConfigStruct switches; + coverCLoadConfigStruct coverC; +}; + +struct coverCalibrationSetting { + unsigned int pin = 0; }; -enum ShCmdEnum { - Idle, - CmdOpen, - CmdClose, - CmdHalt + +struct AlpacaPortsStruct{ + unsigned int remotePort = 32227; + unsigned int alpacaPort = 4567; }; -struct DomeStruct{ - ShCmdEnum ShutterCommand; - ShStEnum ShutterState; - ShInEnum ShutterInputState; - int Cycle; - bool MoveRetry; - unsigned int LastDomeCommand =0; - unsigned long LastServerRequest; +struct ConfigStruct{ + saveConfigStruct save; + validConfig read; + domeConfig dome; + coverCalibrationSetting coverC; + switchConfig switches; + AlpacaPortsStruct alpacaPort; }; -DomeStruct Dome; - -/** END DOME DATA **/ - -/** SWITCH STRUCT **/ -struct SwtichStruct -{ - String Name; - String Description; - uint8_t pin = 0; - int minValue = 0; - int maxValue = 1; - bool CanSet = false; - int Step = 1; - bool analog = false; - int anaValue = 0; - int pwmChannel = -1; - int type; +ConfigStruct Config; +/* END OF CONFIG */ + + + +/* GLOBAL VARIABLES */ +struct upTimeStruct{ + unsigned long previousMillis = 0; + unsigned long minutes = 0; }; -#define _MAX_SWITCH_ID_ 16 - -SwtichStruct Switch[_MAX_SWITCH_ID_]; -/** END SWITCH STRUCT **/ -unsigned int pwmchannles = 1; -//channel 0 is reserved to coverCalibrator - -/** SETTING STRUCT **/ -typedef struct{ - uint8_t pinStart; - uint8_t pinHalt; - uint8_t pinOpen; - uint8_t pinClose; - unsigned long movingTimeOut = 20; - bool enAutoClose; - unsigned long autoCloseTimeOut = 20; -} domeSetting; - -typedef struct{ - unsigned int maxSwitch; -} switchSetting; - -typedef struct{ - unsigned int pin = 0; -} coverCalibrationSetting; +struct wifiReconntectionStruct{ + unsigned long intervall = 30000; + unsigned long lastMillis = 0; + bool waitToReconnect = false; +}; +struct wifiStruct{ + wifiReconntectionStruct reconnection; + upTimeStruct upTime; +}; -typedef struct { - domeSetting dome; - switchSetting switches; - coverCalibrationSetting coverCalibration; -}boardSetting; +struct esp32Struct{ + upTimeStruct upTime; +}; -boardSetting setting; -/**END SETTING STRUCT **/ +struct globalVariable{ + unsigned long upTimeInterval = 60000; + esp32Struct esp32; + wifiStruct wifi; +}; +globalVariable Global; + + +/* END OF GLOBAL */ + + +//common function to validate a pin usage + +bool validatePin(int pin, int type){ + + // pin from 6 to 11 are connected to integrated spi + //pin 0 should be low to enter in flash mode, so I avoid to use it. + if (pin == 0 || (pin >= 6 && pin <= 11)){ + return false; + Serial.print(F("Pin validation error: cannot be used in any way ")); + Serial.println(pin); + } + + switch(type){ + case 1: //Digital Output + case 3: //PWM Output + return pin >=34 ? false : true; + break; + case 2: //Digital Input + return pin >= 4 ? true : false; + break; + case 4: //Analog Input + if( + pin == 2 || + pin == 4 || + (pin >= 12 && pin <= 15) || + (pin >= 25 && pin <= 27) || + (pin >= 32 && pin <= 39) ) + { return true; } else { return false;} + break; + + default: + return false; + break; + } +} diff --git a/src/loop.h b/src/loop.h new file mode 100644 index 0000000..9e8efcc --- /dev/null +++ b/src/loop.h @@ -0,0 +1,49 @@ +#ifndef LOOP +#define LOOP + +void main_loop(){ + + saveConfig(); + #ifdef DOME + domehandlerloop(); + #endif + + #ifdef SWITCH + switchLoop(); + #endif + + ElegantOTA.loop(); + unsigned long currentMillis = millis(); + + //get esp32 uptime + if (currentMillis - Global.esp32.upTime.previousMillis > Global.upTimeInterval){ + Global.esp32.upTime.minutes +=1; + Global.esp32.upTime.previousMillis = currentMillis; + } + + //get wifi uptime and handle reconnection + if(WiFi.status() == WL_CONNECTED ){ + Global.wifi.reconnection.waitToReconnect = false; + if (currentMillis - Global.esp32.upTime.previousMillis > Global.upTimeInterval){ + Global.wifi.upTime.minutes +=1; + } + } else { + Global.wifi.upTime.previousMillis = currentMillis; + if (Global.wifi.reconnection.waitToReconnect == false){ + Global.wifi.reconnection.waitToReconnect = true; + Global.wifi.reconnection.lastMillis = currentMillis; + } + if (currentMillis - Global.wifi.reconnection.lastMillis >= Global.wifi.reconnection.intervall) { + WiFi.disconnect(); + WiFi.reconnect(); + Global.wifi.upTime.minutes = 0; + } + } + +} + + + + + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..ee14e78 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,116 @@ +#define DOME +#define SWITCH +#define COVERC + +#include +#include +#include "AsyncJson.h" +#include "AsyncUDP.h" +#include "HTTPClient.h" +#include +#include +#include +#include "SPIFFS.h" +#include "Dome/domeVariable.h" +#include "Switches/switchVariable.h" +#include "CoverC/coverVariable.h" +#include "header.h" +#include + +AsyncWebServer server(80); +AsyncWebServer Alpserver(4567); + +#include "Alpaca/AlpacaManageFunction.h" +#ifdef DOME +#include "Dome/dome.h" +#endif + +#ifdef SWITCH +#include "Switches/switch.h" +#endif + +#ifdef COVERC +#include "CoverC/cover.h" +#endif +#include "browserServer.h" +#include "configuration.h" + +#include "loop.h" +DNSServer dns; +AsyncUDP udp; + +void ServerNotFound(AsyncWebServerRequest *request) { + request->send(404, "text/plain", "Not found"); + Serial.println("404"); + Serial.println(request->url()); +} + +void setup() +{ + Serial.begin(115200); + AlpacaData.serverTransactionID = 0; +/* reading configuration from file */ + if (!SPIFFS.begin()) { Serial.println("An Error has occurred while mounting SPIFFS"); return; } + + #ifdef DOME + initDomeConfig(); + #endif + + #ifdef SWITCH + initSwitchConfig(); + #endif + + #ifdef COVERC + initCoverCConfig(); + #endif + + Serial.println("Listening for discovery requests..."); + AsyncWiFiManager wifiManager(&server,&dns); + wifiManager.autoConnect("TeslaBoard"); + Serial.print("Connect with IP Address: "); + Serial.println(WiFi.localIP()); + + + if (udp.listen(4567)) + { + Serial.println("Listening for discovery requests..."); + udp.onPacket([](AsyncUDPPacket packet) { + if (packet.length() < 16) + { + return; + } + //Compare packet to Alpaca Discovery string + if (strncmp("alpacadiscovery1", (char *)packet.data(), 16) != 0) + { + return; + } + packet.printf("{\"alpacaport\": 4567}"); + }); + } + + Alpserver.onNotFound(notFound); + /*** MANAGE AREA ***/ + + AlpacaManager(); + #ifdef DOME + domeServer(); + #endif + #ifdef SWITCH + switchServer(); + #endif + + #ifdef COVERC + coverServer(); + #endif + + browserServer(); + + /** END SWITCH SPECIFIC METHODS **/ + Alpserver.begin(); + ElegantOTA.begin(&server); + server.begin(); +} + +void loop(){ + main_loop(); +} diff --git a/src/switchhandler.h b/src/switchhandler.h deleted file mode 100644 index a8e46f2..0000000 --- a/src/switchhandler.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef SWITCH_HAND -#define SWITCH_HAND - - - - -void switchSetup() { - int i=0; -/* Switch Setup */ - -/* Default Switch setting - - pin -> Choose the GPIO where switch is plugged on! - minValue -> Min Value the switch can have (default is 0 and is set to 0 if Switch is Output) - maxValue -> Max Value the switch can have (default is 1 and is forced to 1 if Switch is Output) - CanSet -> Default: true, if true is output or pwm, if false is an input - Step -> Choose the step for change the value of Switch (default 1 and forced to 1 if is output) - analog -> Default is false, if true this switch is PWM - pwmChannel -> Default -1, the value can be 0..15 according to esp32 pwm channels - -Please refer to this page to understand wich output/input you can use without problems: -https://randomnerdtutorials.com/esp32-pinout-reference-gpios/ -*/ - - -/* automatic setup for Switch */ - - for (i=0;i<_MAX_SWITCH_ID_;i++){ - if(Switch[i].pin == 0 || Switch[i].type == 0 ){ - Switch[i].Name =""; - Switch[i].Description =""; - } - if (Switch[i].CanSet == true){ - if (Switch[i].analog == false){ - //Uscita Digitale - pinMode(Switch[i].pin, OUTPUT); - Switch[i].Step = 1; - Switch[i].minValue = 0; - Switch[i].maxValue = 1; - } else { - //Uscita PWM - ledcAttachPin(Switch[i].pin, pwmchannles); - ledcSetup(pwmchannles, 5000, 13); - Switch[i].pwmChannel = pwmchannles; - Switch[i].minValue = 0; - Switch[i].maxValue = 8192; - pwmchannles++; - } - } else { - if (Switch[i].analog == false){ - //Ingresso Digitale - pinMode(Switch[i].pin, INPUT); - Switch[i].Step = 1; - Switch[i].minValue = 0; - Switch[i].maxValue = 1; - } else { - //Ingresso Analogico - Switch[i].minValue = 0; - Switch[i].maxValue = 4095; - } - } - } -} - -#endif From 8e5bfed0ebad860adfd67a654134acb89e428f63 Mon Sep 17 00:00:00 2001 From: StefanoTesla Date: Mon, 6 May 2024 15:12:56 +0200 Subject: [PATCH 2/5] lots of bugs solved DO NOT USE IN PRODUCTION! --- data/switchconfig.txt | 2 +- html_pages/index.html | 103 +++- html_pages/package-lock.json | 797 ++++++++++++++++++++++-------- html_pages/setup.html | 39 +- src/Alpaca/alpacamanagefunction.h | 2 +- src/CoverC/webserver.h | 17 +- src/Dome/webserver.h | 92 ++-- src/Switches/switch.h | 7 +- src/Switches/webserver.h | 26 +- src/browserServer.h | 71 +-- src/configuration.h | 1 + src/loop.h | 9 +- src/main.cpp | 7 +- 13 files changed, 822 insertions(+), 351 deletions(-) diff --git a/data/switchconfig.txt b/data/switchconfig.txt index 70670eb..b416a37 100644 --- a/data/switchconfig.txt +++ b/data/switchconfig.txt @@ -1 +1 @@ -[{"name":"Sh Open","desc":"Shutter open","type":2,"pin":34,"min":0,"max":1},{"name":"Sh Closed","desc":"Shutter Chiuso","type":2,"pin":35,"min":0,"max":1},{"name":"Switch 3","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"Switch 4","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"Switch 5","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"Switch 6","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"","desc":"","type":0,"pin":99,"min":0,"max":1},{"name":"","desc":"","type":0,"pin":99,"min":0,"max":1}] \ No newline at end of file +[{"name":"Camera","desc":"","type":1,"pin":18},{"name":"Hub","desc":"","type":1,"pin":19},{"name":"Scorta 1","desc":"","type":1,"pin":17},{"name":"Scorta 2","desc":"","type":1,"pin":16},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0},{"name":"","desc":"","type":0,"pin":0}] \ No newline at end of file diff --git a/html_pages/index.html b/html_pages/index.html index 0f7281c..a1a1807 100644 --- a/html_pages/index.html +++ b/html_pages/index.html @@ -1,3 +1,4 @@ + @@ -127,22 +128,22 @@

StefanoTesla Dome&Switch

-