diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..3127af3 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,22 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:lolin_d32] +platform = espressif32 +board = lolin_d32 +framework = arduino +lib_deps = + arduino-libraries/NTPClient@^3.2.1 + greiman/SSD1306Ascii@^1.3.3 + thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 + knolleary/PubSubClient@^2.8 + tobiasschuerg/ESP8266 Influxdb@^3.12.1 +monitor_speed = 115200 +;upload_port = COM3 \ No newline at end of file diff --git a/src/OTA.h b/src/OTA.h new file mode 100644 index 0000000..dbdebe9 --- /dev/null +++ b/src/OTA.h @@ -0,0 +1,96 @@ +#ifdef ESP32 +#include +#include +#else +#include +#include +#endif + +#include +#include + +#if defined(ESP32_RTOS) && defined(ESP32) +void ota_handle( void * parameter ) { + for (;;) { + ArduinoOTA.handle(); + delay(3500); + } +} +#endif + +void setupOTA(const char* nameprefix, const char* ssid, const char* password) { + // Configure the hostname + uint16_t maxlen = strlen(nameprefix) + 7; + char *fullhostname = new char[maxlen]; + uint8_t mac[6]; + WiFi.macAddress(mac); + snprintf(fullhostname, maxlen, "%s-%02x%02x%02x", nameprefix, mac[3], mac[4], mac[5]); + ArduinoOTA.setHostname(fullhostname); + delete[] fullhostname; + + // Configure and start the WiFi station + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + + // Wait for connection + while (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("Connection Failed! Rebooting..."); + delay(5000); + ESP.restart(); + } + + // Port defaults to 3232 + // ArduinoOTA.setPort(3232); // Use 8266 port if you are working in Sloeber IDE, it is fixed there and not adjustable + + // No authentication by default + // ArduinoOTA.setPassword("admin"); + + // Password can be set with it's md5 value as well + // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 + // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); + + ArduinoOTA.onStart([]() { + //NOTE: make .detach() here for all functions called by Ticker.h library - not to interrupt transfer process in any way. + String type; + if (ArduinoOTA.getCommand() == U_FLASH) + type = "sketch"; + else // U_SPIFFS + type = "filesystem"; + + // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() + Serial.println("Start updating " + type); + }); + + ArduinoOTA.onEnd([]() { + Serial.println("\nEnd"); + }); + + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + }); + + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println("\nAuth Failed"); + else if (error == OTA_BEGIN_ERROR) Serial.println("\nBegin Failed"); + else if (error == OTA_CONNECT_ERROR) Serial.println("\nConnect Failed"); + else if (error == OTA_RECEIVE_ERROR) Serial.println("\nReceive Failed"); + else if (error == OTA_END_ERROR) Serial.println("\nEnd Failed"); + }); + + ArduinoOTA.begin(); + + Serial.println("OTA Initialized"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + +#if defined(ESP32_RTOS) && defined(ESP32) + xTaskCreate( + ota_handle, /* Task function. */ + "OTA_HANDLE", /* String with name of task. */ + 10000, /* Stack size in bytes. */ + NULL, /* Parameter passed as input of the task */ + 1, /* Priority of the task. */ + NULL); /* Task handle. */ +#endif +} \ No newline at end of file diff --git a/src/credentials.h b/src/credentials.h new file mode 100644 index 0000000..938cde5 --- /dev/null +++ b/src/credentials.h @@ -0,0 +1,3 @@ +#pragma once +const char* mySSID = "pipanet"; +const char* myPASSWORD = "passatvr6"; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..9e0a8ba --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,300 @@ +//#define BME280 Tempatur Luftdruck etc Sensor +//#define PAM8302 // Verstärker Sound + +#include +#include "OTA.h" +#include "credentials.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +const char* ntpServer = "pool.ntp.org"; +const long gmtOffset_sec = 0; +const int daylightOffset_sec = 3600; + +// #define FlyingFisch Lichtsensor +time_t now; +tm tm; +String TimeStamp; + +// ### Display +SSD1306Wire display(0x3c,5,4); +// ### IO +/* +int Analog_Eingang = 36; // Analogwert +int Digital_Eingang = 26; // Binärer Wert +int analog_temp = 0; +int digital_temp = 0; +double Analog; +int Digital; +char buffer[10]; +*/ + +// Assign output variables to GPIO pins +const int output26 = 26; +const int output25 = 25; +// Input +const int input36 = 36; +const int input39 = 16; + +// restart automatisch +boolean auto1 = true; +boolean auto2 = true; +boolean auto1start = false; +unsigned long auto1timer = 0; +unsigned long now1is = 0; +const long now1max = 10000; +boolean auto2start = false; +unsigned long auto2timer = 0; +unsigned long now2is = 0; +const long now2max = 10000; +// Current time +unsigned long currentTime = millis(); +// Previous time +unsigned long previousTime = 0; +// Define timeout time in milliseconds (example: 2000ms = 2s) +const long timeoutTime = 2000; + +int retry = 0; + + + +// ### Webserver +WebServer server(80); +String htmltext; +String sended; +void setHtml(){ + htmltext = ""; + htmltext += "

Uhrzeit

"; + htmltext += "

" + String(TimeStamp) + "

"; + htmltext += "

Server Status

"; + htmltext += "

"; + htmltext += "

"; + if (auto1== true) { + htmltext += "

"; + } + else { + htmltext += "

"; + } + if (digitalRead(input36)== HIGH){ + htmltext += "

Server 1 ist online

"; + } else { + htmltext += "

Server 1 ist offline

"; + } + + htmltext += "

"; + htmltext += "

"; + if (auto2== true) { + htmltext += "

"; + } + else { + htmltext += "

"; + } + if (digitalRead(input39)== HIGH){ + htmltext += "

Server 2 ist online

"; + } else { + htmltext += "

Server 2 ist offline

"; + } + +} + +String SendHTML(String addtext){ + String ptr = ""; + ptr += "\n"; + ptr += "\n"; + ptr += "\n"; + ptr += "Gaszaehler Webserver\n"; + ptr += "\n"; + ptr += "\n"; + ptr += "\n"; + ptr += "\n"; + ptr += "

Webserver

\n"; + ptr += addtext; + ptr += "\n"; + ptr += ""; + return ptr; +} + +void handleCss() +{ + String message = ""; + message += "*{font-family:sans-serif}\n"; + message += "body{margin:10px;width:300px}\n"; + message += "h1, h2{color:white;background:#8FCE00;text-align:center}\n"; + message += "h1{font-size:1.2em;margin:1px;padding:5px}\n"; + message += "h2{font-size:1.0em}\n"; + message += "h3{font-size:0.9em}\n"; + message += "a{text-decoration:none;color:dimgray;text-align:center}\n"; + message += ".small{font-size:0.6em}\n"; + message += ".value{font-size:1.8em;text-align:center;line-height:50%}\n"; + message += "footer p, .infodaten p{font-size:0.7em;color:dimgray;background:silver;"; + message += "text-align:center;margin-bottom:5px}\n"; + message += "nav{background-color:silver;margin:1px;padding:5px;font-size:0.8em}\n"; + message += "nav a{color:white;padding:10px;text-decoration:none}\n"; + message += "nav a:hover{text-decoration:underline}\n"; + message += "nav p{margin:0px;padding:0px}\n"; + message += ".button{background-color:#C0C0C0;color:dimgray;text-decoration:none;"; + message += "border-style:solid;border-color:dimgray;width:150}\n"; + message += ".button2 {background-color: #555555;}\n"; + message += ".on, .off{margin-top:0;margin-bottom:0.2em;margin-left:3em;"; + message += "font-size:1.4em;background-color:#C0C0C0;"; + message += "border-style:solid;width:5em;height:1.5em;text-decoration:none;text-align:center}\n"; + message += ".on{border-color:green}\n)"; + server.send(200, "text/css", message); +} + +void handle_OnData() {server.send(200, "text/html", SendHTML(htmltext)); } +void handle_OnConnect() {server.send(200, "text/html", SendHTML("Boot")); } +void handle_NotFound(){server.send(404, "text/plain", "Not found");} + +// Oled Display +void printStatus(){ + display.clear(); + display.drawString(0,0,"IP: "+WiFi.localIP().toString()+" ;)"); + long rssi = WiFi.RSSI(); + char rssiStr[255]; + sprintf(rssiStr,"RSSID: %d dBm",rssi); + display.drawString(0,11,rssiStr); + time(&now); // read the current time + localtime_r(&now, &tm); // update the structure tm with the current time + TimeStamp = String(tm.tm_mday) + "." + String(tm.tm_mon + 1) + "." + String(tm.tm_year + 1900) + " " + String(tm.tm_hour) + ":" + String(tm.tm_min) + ":" + String(tm.tm_sec); + display.drawString(0,22,TimeStamp); + String vStr; + display.drawString(0,33,vStr); + + display.display(); +} + + + +unsigned long pubTime; +float tst; + +void auto1on(){ + auto1= true; + server.sendHeader("Location","/"); + server.send(303); +} +void auto1off(){ + auto1= false; + server.sendHeader("Location","/"); + server.send(303); +} +void pw1on(){ + digitalWrite(output25, HIGH); + delay(200); + digitalWrite(output25,LOW); + server.sendHeader("Location","/"); + server.send(303); +} +void pw1off(){ + digitalWrite(output25, HIGH); + delay(5000); + digitalWrite(output25,LOW); + server.sendHeader("Location","/"); + server.send(303); +} +void auto2on(){ + auto2= true; + server.sendHeader("Location","/"); + server.send(303); +} +void auto2off(){ + auto2= false; + server.sendHeader("Location","/"); + server.send(303); +} +void pw2on(){ + digitalWrite(output26, HIGH); + delay(200); + digitalWrite(output26,LOW); + server.sendHeader("Location","/"); + server.send(303); +} +void pw2off(){ + digitalWrite(output26, HIGH); + delay(5000); + digitalWrite(output26,LOW); + server.sendHeader("Location","/"); + server.send(303); +} + +void setup() { + Serial.begin(115200); + Serial.println("Booting"); + setupOTA("Template", mySSID, myPASSWORD); + // Initialize the output variables as outputs + pinMode(output26, OUTPUT); + pinMode(output25, OUTPUT); + // Set outputs to LOW + digitalWrite(output26, LOW); + digitalWrite(output25, LOW); + // check server running + // SVP server 1 + pinMode(input36, INPUT); + // SVN server 2 + pinMode(input39, INPUT); + + display.init(); + //display.flipScreenVertically(); + display.setFont(ArialMT_Plain_10); + configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); + server.on("/", handle_OnData); + server.on("/f.css", handleCss); + server.on("/auto1/on",auto1on); + server.on("/auto1/off",auto1off); + server.on("/pw1/on",pw1on); + server.on("/pw1/off",pw1off); + server.on("/auto2/on",auto2on); + server.on("/auto2/off",auto2off); + server.on("/pw2/on",pw2on); + server.on("/pw2/off",pw2off); + + server.begin(); + +} + +void loop() { +#ifdef defined(ESP32_RTOS) && defined(ESP32) +#else // If you do not use FreeRTOS, you have to regulary call the handle method. + ArduinoOTA.handle(); +#endif + printStatus(); + server.handleClient(); + setHtml(); + if ((auto1 == true) && (digitalRead(input36)== LOW)){ + if (auto1start== true){ + digitalWrite(output25, HIGH); + delay(200); + digitalWrite(output25,LOW); + auto1start = false; + auto1timer = millis(); + } else { + now1is = millis(); + if ( now1is - auto1timer > now1max){ + auto1start = true; + } + } + } + if ((auto2 == true) && (digitalRead(input39)== LOW)){ + if (auto2start== true){ + digitalWrite(output26, HIGH); + delay(200); + digitalWrite(output26,LOW); + auto2start = false; + auto2timer = millis(); + } else { + now2is = millis(); + if ( now2is - auto2timer > now2max){ + auto2start = true; + } + } + } +} \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html