EPS8266 WEB LED Control + JSON + SPIFFS
by claasworks in Circuits > Arduino
627 Views, 1 Favorites, 0 Comments
EPS8266 WEB LED Control + JSON + SPIFFS
Am Ende des LED Projekts werden 16 LED mit einem I2C Treiber über eine Weboberfläche per WLAN angesteuert.
In der finalen Oberfläche werden die LED über einen Raumplan gesteuert und visualisiert.
.
Im ersten Teil hatte ich die Hardware und eine kleine Startseite für die LEDs erstellt.
Im zweiten Teil habe ich eine Weboberfläche mit Raumplan für die einzelnen LEDs erstellt, die LED PWM Werte werden mittels JSON (JavaScript) zurückgelesen und es gibt eine Uploadmöglichkeit für Grafiken, CSS, JS und die html Seite.
Es muss nun nicht mehr der Sketch für Anpassungen an der Weboberfläche neu hochgeladen werden und es erfolgt kein reload der Seite beim Wechsel einer LED Einstellung. =)
Erwiterungen in CaptivePortalAdvanced.ino
In der CaptivePortalAdvanced.ino Datei ist SPIFFS für das file handling und der Servereintrag ./readLED hinzugekommen.
#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <DNSServer.h> #include <ESP8266mDNS.h> #include <EEPROM.h> #include <Wire.h> /* This example serves a "hello world" on a WLAN and a SoftAP at the same time. The SoftAP allow you to configure WLAN parameters at run time. They are not setup in the sketch but saved on EEPROM. Connect your computer or cell phone to wifi network ESP_ap with password 12345678. A popup may appear and it allow you to go to WLAN config. If it does not then navigate to <a href="http://192.168.4.1/wifi"> <a href="http://192.168.4.1/wifi" rel="nofollow"> http://192.168.4.1/wifi </a> </a> and config it there. Then wait for the module to connect to your wifi and take note of the WLAN IP it got. Then you can disconnect from ESP_ap and return to your regular WLAN. Now the ESP8266 is in your network. You can reach it through <a href="http://192.168.x.x/"> <a href="http://192.168.4.1/wifi" rel="nofollow"> http://192.168.4.1/wifi </a> </a> (the IP you took note of) or maybe at <a href="http://esp8266.local"> <a href="http://192.168.4.1/wifi" rel="nofollow"> http://192.168.4.1/wifi </a> </a> too. This is a captive portal because through the softAP it will redirect any http request to <a href="http://192.168.4.1/"> <a href="http://192.168.4.1/wifi" rel="nofollow"> http://192.168.4.1/wifi </a> </a> */ //////////////////////////// PINs ///////////////////////////////// // LED #define BLINKPIN D8 // Status LED indicates a wifi / user interaction #define BLINKPIN_TOGGLE() (digitalWrite(BLINKPIN, !digitalRead(BLINKPIN))) #define BLINKPIN_ON() (digitalWrite(BLINKPIN, HIGH)) #define BLINKPIN_OFF() (digitalWrite(BLINKPIN, LOW)) //I2C TLC59116 #define TLC59116_SCL D1 #define TLC59116_SDA D2 //////////////////////////// TLC59116 ///////////////////////////////// // Demo für I2C-LED-Treiber mit TLC59116 // ELV-AG Leer // letzte Änderung 21.4.2011 // I2C -Adresse = 0C hex (alle Jumper A0 bis A3 offen) // Hinweis zur Slaveadresse: // Da bei der "Wire"-Funktion entfällt das letzte Bit, das für Lesen oder Schreiben (R/W) steht. // Die Adresse hat somit nur noch 7 Bit, und sieht am Beispiel von C0hex so aus : 1100000b (60hex) // 8Bit : 11000000 = C0h // 7Bit : 1100000 = 60h #define BRIGHTNESS 32 // init max. 255 int BRIGHTNESS_var = 8; int BRIGHTNESS_Array[16]={64,64,64,64, 64,64,64,64, 64,64,64,64, 64,64,64,64}; String BRIGHTNESS_string = "NULL"; //html <=> js //////////////////////////// SPIFFS / fsUploadFile ///////////////////////////////// #include <FS.h> unsigned long Speicherbelegung = 0; File fsUploadFile; // a File object to temporarily store the received file String getContentType(String filename); // convert the file extension to the MIME type bool handleFileRead(String path); // send the right file to the client (if it exists) void handleFileUpload(); // upload a new file to the SPIFFS String Page404upload = "<html><head></head><body><form method='post' enctype='multipart/form-data'><input type='file' name='name'><input class='button' type='submit' value='Upload'></form></body></html>"; /* Set these to your desired softAP credentials. They are not configurable at runtime */ #ifndef APSSID #define APSSID "ESP_LED_TLC59116" #define APPSK "12345678" #endif const char *softAP_ssid = APSSID; const char *softAP_password = APPSK; /* hostname for mDNS. Should work at least on windows. Try <a href="http://esp8266.local"> <a href="http://esp8266.local" rel="nofollow"> http://192.168.4.1/wifi </a> </a> */ const char *myHostname = "esp8266"; /* Don't set this wifi credentials. They are configurated at runtime and stored on EEPROM */ char ssid[32] = ""; char password[32] = ""; // DNS server const byte DNS_PORT = 53; DNSServer dnsServer; // Web server ESP8266WebServer server(80); /* Soft AP network parameters */ IPAddress apIP(172, 217, 28, 1); IPAddress netMsk(255, 255, 255, 0); /** Should I connect to WLAN asap? */ boolean connect; /** Last time I tried to connect to WLAN */ unsigned long lastConnectTry = 0; /** Current WLAN status */ unsigned int status = WL_IDLE_STATUS; void setup() { pinMode(BLINKPIN, OUTPUT); // Set pin as output BLINKPIN_ON(); delay(1000); Serial.begin(9600); Serial.println(); Serial.println("Configuring access point..."); /* You can remove the password parameter if you want the AP to be open. */ WiFi.softAPConfig(apIP, apIP, netMsk); WiFi.softAP(softAP_ssid, softAP_password); delay(500); // Without delay I've seen the IP address blank Serial.print("AP IP address: "); Serial.println(WiFi.softAPIP()); /* Setup the DNS server redirecting all the domains to the apIP */ dnsServer.setErrorReplyCode(DNSReplyCode::NoError); dnsServer.start(DNS_PORT, "*", apIP); /* Init SPIFFS */ if (!SPIFFS.begin()) { Serial.println("SPIFFS nicht initialisiert! Stop!"); while (1) yield(); } else { Dir dir = SPIFFS.openDir("/"); while (dir.next()) { String fileName = dir.fileName(); size_t fileSize = dir.fileSize(); Speicherbelegung += fileSize; Serial.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str()); } Serial.printf("\n"); Serial.printf("Speicherbelegung: %s\n", formatBytes(Speicherbelegung).c_str()); Serial.printf("\n"); } server.serveStatic("/", SPIFFS, "/index.html"); server.serveStatic("/img", SPIFFS, "/img"); server.serveStatic("/js", SPIFFS, "/js"); server.serveStatic("/css", SPIFFS, "/css"); server.serveStatic("/dat", SPIFFS, "/data"); /* Setup web page: file uploads */ server.on("/upload", HTTP_GET, []() { // if the client requests the upload page if (!handleFileRead("/upload.html")) // send it if it exists server.send(404, "text/html", Page404upload); } ); server.on("/upload", HTTP_POST, // if the client posts to the upload page [](){ server.send(200); }, // Send status 200 (OK) to tell the client we are ready to receive handleFileUpload // Receive and save the file ); /* Setup web pages: LED on/off + js LED status*/ server.on("/LEDswitch", handleLED_switch); server.on("/readLED", handleStatusLED); /* Setup web pages: I2C info on COM port */ server.on("/i2c", handleStatusI2C); /* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */ //server.on("/", handleRoot); //old server.on("/",HTTP_GET,handleRoot); // Files SPIFFS server.on("/wifi", handleWifi); server.on("/wifisave", handleWifiSave); server.on("/generate_204", handleRoot); //Android captive portal. Maybe not needed. Might be handled by notFound handler. server.on("/fwlink", handleRoot); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. server.onNotFound(handleNotFound); server.begin(); // Web server start Serial.println("HTTP server started"); loadCredentials(); // Load WLAN credentials from network connect = strlen(ssid) > 0; // Request WLAN connect if there is a SSID init_TLC59116(); Set_LED_ALL(BRIGHTNESS); BLINKPIN_OFF(); } void connectWifi() { Serial.println("Connecting as wifi client..."); WiFi.disconnect(); WiFi.begin(ssid, password); int connRes = WiFi.waitForConnectResult(); Serial.print("connRes: "); Serial.println(connRes); } void loop() { if (connect) { Serial.println("Connect requested"); connect = false; connectWifi(); lastConnectTry = millis(); } { unsigned int s = WiFi.status(); if (s == 0 && millis() > (lastConnectTry + 60000)) { /* If WLAN disconnected and idle try to connect */ /* Don't set retry time too low as retry interfere the softAP operation */ connect = true; } if (status != s) { // WLAN status change Serial.print("Status: "); Serial.println(s); status = s; if (s == WL_CONNECTED) { /* Just connected to WLAN */ Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); // Setup MDNS responder if (!MDNS.begin(myHostname)) { Serial.println("Error setting up MDNS responder!"); } else { Serial.println("mDNS responder started"); // Add service to MDNS-SD MDNS.addService("http", "tcp", 80); } } else if (s == WL_NO_SSID_AVAIL) { WiFi.disconnect(); } } if (s == WL_CONNECTED) { MDNS.update(); } } // Do work: //DNS dnsServer.processNextRequest(); //HTTP server.handleClient(); }
Erwiterungen in Credentials.ino
keine
/** Load WLAN credentials from EEPROM */ void loadCredentials() { EEPROM.begin(512); EEPROM.get(0, ssid); EEPROM.get(0 + sizeof(ssid), password); char ok[2 + 1]; EEPROM.get(0 + sizeof(ssid) + sizeof(password), ok); EEPROM.end(); if (String(ok) != String("OK")) { ssid[0] = 0; password[0] = 0; } Serial.println("Recovered credentials:"); Serial.println(ssid); Serial.println(strlen(password) > 0 ? "********" : ""); } /** Store WLAN credentials to EEPROM */ void saveCredentials() { EEPROM.begin(512); EEPROM.put(0, ssid); EEPROM.put(0 + sizeof(ssid), password); char ok[2 + 1] = "OK"; EEPROM.put(0 + sizeof(ssid) + sizeof(password), ok); EEPROM.commit(); EEPROM.end(); }
Erwiterungen in HandleHttp.ino
Das alte handleRoot() wurde vereinfacht.
Es sind (SPIFFS) Funktionen für die Bearbeitung von Dateien hinzugekommen. (Upload und html Server)
Im LED Funktionsbereich ist die Funktionen handleFileRead() für Rückgabe von LED PWM ergänzt worden.
/** Handle root or redirect to captive portal */ //void handleRoot() { // if (captivePortal()) { // If caprive portal redirect instead of displaying the page. // return; // } // server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // server.sendHeader("Pragma", "no-cache"); // server.sendHeader("Expires", "-1"); // // String Page; // Page += F( // "<html><head></head><body>" // "<h1>HELLO WORLD!!</h1>"); // if (server.client().localIP() == apIP) { // Page += String(F("<p>You are connected through the soft AP: ")) + softAP_ssid + F("</p>"); // } else { // Page += String(F("<p>You are connected through the wifi network: ")) + ssid + F("</p>"); // } ///** Handle LED Control*/ // // Page += // String(F( // "\r\n<br />" // "<table><tr><th align='left'>LED Control</th></tr>" // "<tr><td>")); // Page += String(F("\r\n<tr><td><a href='/LEDswitch'> all LED </a></td></tr>")); // // for (int i = 1; i < 17; i++) { // Page += String(F("\r\n<tr><td><a href='/LEDswitch?LED=")) + i + (F("'>LED")) + i + (F("</a></td></tr>")); // } // // Page += // String(F( // "</td></tr>" // "</table>" // "\r\n<br />")); // // Page += F( // "<p>You may want to test the <a href='/i2c'>I2C status</a>. (COM port)</p>"); // // Page += F( // "<p>You may want to <a href='/wifi'>config the wifi connection</a>.</p>" // "</body></html>"); // // server.send(200, "text/html", Page); //} /** Handle root or redirect to captive portal (Files SPIFFS)*/ void handleRoot() { Serial.printf("handleRoot"); if (!handleFileRead(server.uri())) server.send(404, "text/plain", "FileNotFound"); } /** Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */ boolean captivePortal() { if (!isIp(server.hostHeader()) && server.hostHeader() != (String(myHostname) + ".local")) { // Serial.println("Request redirected to captive portal"); server.sendHeader("Location", String("http://") + toStringIp(server.client().localIP()), true); server.send(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. server.client().stop(); // Stop is needed because we sent no content length return true; } return false; } /** Wifi config page handler */ void handleWifi() { server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); server.sendHeader("Expires", "-1"); String Page; Page += F( "<html><head></head><body>" "<h1>Wifi config</h1>"); if (server.client().localIP() == apIP) { Page += String(F("<p>You are connected through the soft AP: ")) + softAP_ssid + F("</p>"); } else { Page += String(F("<p>You are connected through the wifi network: ")) + ssid + F("</p>"); } Page += String(F( "\r\n<br />" "<table><tr><th align='left'>SoftAP config</th></tr>" "<tr><td>SSID ")) + String(softAP_ssid) + F("</td></tr>" "<tr><td>IP ") + toStringIp(WiFi.softAPIP()) + F("</td></tr>" "</table>" "\r\n<br />" "<table><tr><th align='left'>WLAN config</th></tr>" "<tr><td>SSID ") + String(ssid) + F("</td></tr>" "<tr><td>IP ") + toStringIp(WiFi.localIP()) + F("</td></tr>" "</table>" "\r\n<br />" "<table><tr><th align='left'>WLAN list (refresh if any missing)</th></tr>"); Serial.println("scan start"); int n = WiFi.scanNetworks(); Serial.println("scan done"); if (n > 0) { for (int i = 0; i < n; i++) { Page += String(F("\r\n<tr><td>SSID ")) + WiFi.SSID(i) + ((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? F(" ") : F(" *")) + F(" (") + WiFi.RSSI(i) + F(")</td></tr>"); } } else { Page += F("<tr><td>No WLAN found</td></tr>"); } Page += F( "</table>" "\r\n<br /><form method='POST' action='wifisave'><h4>Connect to network:</h4>" "<input type='text' placeholder='network' name='n'/>" "<br /><input type='password' placeholder='password' name='p'/>" "<br /><input type='submit' value='Connect/Disconnect'/></form>" "<p>You may want to <a href='/'>return to the home page</a>.</p>" "</body></html>"); server.send(200, "text/html", Page); server.client().stop(); // Stop is needed because we sent no content length } /** Handle the WLAN save form and redirect to WLAN config page again */ void handleWifiSave() { Serial.println("wifi save"); server.arg("n").toCharArray(ssid, sizeof(ssid) - 1); server.arg("p").toCharArray(password, sizeof(password) - 1); server.sendHeader("Location", "wifi", true); server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); server.sendHeader("Expires", "-1"); server.send(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. server.client().stop(); // Stop is needed because we sent no content length saveCredentials(); connect = strlen(ssid) > 0; // Request WLAN connect with new credentials if there is a SSID } void handleNotFound() { if (captivePortal()) { // If caprive portal redirect instead of displaying the error page. return; } String message = F("File Not Found\n\n"); message += F("URI: "); message += server.uri(); message += F("\nMethod: "); message += (server.method() == HTTP_GET) ? "GET" : "POST"; message += F("\nArguments: "); message += server.args(); message += F("\n"); for (uint8_t i = 0; i < server.args(); i++) { message += String(F(" ")) + server.argName(i) + F(": ") + server.arg(i) + F("\n"); } server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); server.sendHeader("Expires", "-1"); server.send(404, "text/plain", message); } /** Handle files SPIFFS */ String getContentType(String filename) { // convert the file extension to the MIME type if (filename.endsWith(".html")) return "text/html"; else if (filename.endsWith(".css")) return "text/css"; else if (filename.endsWith(".js")) return "application/javascript"; else if (filename.endsWith(".ico")) return "image/x-icon"; else if (filename.endsWith(".jpg")) return "image/jpeg"; else if (filename.endsWith(".gif")) return "image/gif"; return "text/plain"; } bool handleFileRead(String path) { // send the right file to the client (if it exists) Serial.println("handleFileRead"); if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file String contentType = getContentType(path); // Get the MIME type String pathWithGz = path + ".gz"; if (SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { // If the file exists, either as a compressed archive, or normal if (SPIFFS.exists(pathWithGz)) // If there's a compressed version available path += ".gz"; // Use the compressed verion File file = SPIFFS.open(path, "r"); // Open the file size_t sent = server.streamFile(file, contentType); // Send it to the client file.close(); // Close the file again Serial.println(String("\tSent file: ") + path); return true; } Serial.println(String("\tFile Not Found: ") + path); // If the file doesn't exist, return false return false; } void handleFileUpload(){ // upload a new file to the SPIFFS String Page; Page += F( "<html><head>" "</head><body>" "<h1>FileUpload</h1>"); HTTPUpload& upload = server.upload(); if(upload.status == UPLOAD_FILE_START){ String filename = upload.filename; // if(!filename.startsWith("/")) filename = "/"+filename; Serial.print("handleFileUpload Name: "); Serial.println(filename); Page += String(F("<p>handleFileUpload Name: ")) + filename + F("</p>"); /* // Opens a file. path should be an absolute path starting with a slash (e.g. /dir/filename.txt). // https://circuits4you.com/2018/01/31/example-of-esp8266-flash-file-system-spiffs/ */ if (filename.endsWith(".jpg")) filename = "/img/"+filename; else if (filename.endsWith(".gif")) filename = "/img/"+filename; else if (filename.endsWith(".png")) filename = "/img/"+filename; else if (filename.endsWith(".css")) filename = "/css/"+filename; else if (filename.endsWith(".js" )) filename = "/js/"+filename; if (!filename.startsWith("/")) filename = "/"+filename; fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist)´ filename = String(); } else if(upload.status == UPLOAD_FILE_WRITE){ if(fsUploadFile) fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file } else if(upload.status == UPLOAD_FILE_END){ if(fsUploadFile) { // If the file was successfully created fsUploadFile.close(); // Close the file again Serial.print("handleFileUpload Size: "); Serial.println(formatBytes(upload.totalSize).c_str()); Serial.println("-------------------------\n"); Page += String(F("<p>handleFileUpload Size: ")) + formatBytes(upload.totalSize).c_str() + F("</p>"); Page += F( "<p>[ <a href='/'>RoomInfo Info</a> ] [ <a href='/wifi'>wifi Info</a> ] [<a href='/upload'> upload </a>]</p>" "</body></html>"); server.send(303, "text/html", Page); // Terminal { Dir dir = SPIFFS.openDir("/"); while (dir.next()) { String fileName = dir.fileName(); size_t fileSize = dir.fileSize(); Speicherbelegung += fileSize; Serial.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str()); } Serial.printf("\n"); Serial.printf("Speicherbelegung: %s\n", formatBytes(Speicherbelegung).c_str()); Serial.printf("\n"); } } else { server.send(500, "text/plain", "500: couldn't create file"); } } } /** Handle the WLAN LED link and redirect to WLAN root page again */ void handleLED_switch() { BLINKPIN_ON(); // server.argName(i) => server.arg(i) int arg1 = 0; if (server.args() > 0){ // Werte vorhanden? arg1 = server.arg(0).toInt(); if ((arg1 <= 16) && (arg1 > 0)) { handleLED_switch_fkt(arg1); } } // server.argName = "" else { if (BRIGHTNESS_var > 127) BRIGHTNESS_var = 0; else if (BRIGHTNESS_var < 128) BRIGHTNESS_var = 255; Set_LED_ALL(BRIGHTNESS_var); } String message = F("URI: "); message += server.uri(); message += F("\nMethod: "); message += (server.method() == HTTP_GET) ? "GET" : "POST"; message += F("\nArguments: "); message += server.args(); message += F("\n"); Serial.print(message); for (uint8_t i = 0; i < server.args(); i++) { message += String(F("> ")) + server.argName(i) + F(": ") + server.arg(i) + F(" <\n"); } server.sendHeader("Location", "/",true); //redirect to WLAN root page server.send(302, "text/plane",""); BLINKPIN_OFF(); } /** send LED PWM Array */ void handleStatusLED() { BLINKPIN_ON(); send_LED_ALL_Array(); server.send(200, "text/plane", BRIGHTNESS_string); // LED value - JSON to client ajax request BLINKPIN_OFF(); } /** Handle the WLAN I2C link and redirect to WLAN root page again */ void handleStatusI2C() { byte error, address; int nDevices; Serial.println("Scanning..."); nDevices = 0; for(address = 1; address < 127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address<16) Serial.print("0"); Serial.print(address,HEX); Serial.println(" !"); nDevices++; } else if (error==4) { Serial.print("Unknown error at address 0x"); if (address<16) Serial.print("0"); Serial.println(address,HEX); } } if (nDevices == 0) Serial.println("No I2C devices found\n"); else Serial.println("done\n"); server.sendHeader("Location", "/",true); //redirect to WLAN root page server.send(302, "text/plane",""); }
Erwiterungen in Tools.ino
Für eine bessere Darstellung der Dateigrößen ist die (SPIFFS) Funktionen formatBytes()
hinzugekommen.
Im LED Funktionsbereich ist die Funktionen send_LED_ALL_Array() für die Stringerstellung
von den LED PWM ergänzt worden.
/** Is this an IP? */ boolean isIp(String str) { for (size_t i = 0; i < str.length(); i++) { int c = str.charAt(i); if (c != '.' && (c < '0' || c > '9')) { return false; } } return true; } /** IP to String? */ String toStringIp(IPAddress ip) { String res = ""; for (int i = 0; i < 3; i++) { res += String((ip >> (8 * i)) & 0xFF) + "."; } res += String(((ip >> 8 * 3)) & 0xFF); return res; } //format bytes / SPIFFS String formatBytes(size_t bytes) { if (bytes < 1024) { return String(bytes) + "B"; } else if (bytes < (1024 * 1024)) { return String(bytes / 1024.0) + "KB"; } else if (bytes < (1024 * 1024 * 1024)) { return String(bytes / 1024.0 / 1024.0) + "MB"; } else { return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB"; } } //////////////////////////// TLC59116 ///////////////////////////////// void init_TLC59116() { Wire.begin(TLC59116_SDA, TLC59116_SCL); // (SDA), (SCL) Wire.beginTransmission(B1100000); // TLC59116 Slave Adresse ->C0 hex Wire.write(0x80); // autoincrement ab Register 0h Wire.write(0x00); // Register 00 / Mode1 Wire.write(0x00); // Register 01 / Mode2 Wire.write(0x00); // Register 02 / PWM LED 1 // Default alle PWM auf 0 Wire.write(0x00); // Register 03 / PWM LED 2 Wire.write(0x00); // Register 04 / PWM LED 3 Wire.write(0x00); // Register 05 / PWM LED 4 Wire.write(0x00); // Register 06 / PWM LED 5 Wire.write(0x00); // Register 07 / PWM LED 6 Wire.write(0x00); // Register 08 / PWM LED 7 Wire.write(0x00); // Register 09 / PWM LED 8 Wire.write(0x00); // Register 0A / PWM LED 9 Wire.write(0x00); // Register 0B / PWM LED 10 Wire.write(0x00); // Register 0C / PWM LED 11 Wire.write(0x00); // Register 0D / PWM LED 12 Wire.write(0x00); // Register 0E / PWM LED 13 Wire.write(0x00); // Register 0F / PWM LED 14 Wire.write(0x00); // Register 10 / PWM LED 15 Wire.write(0x00); // Register 11 / PWM LED 16 // Default alle PWM auf 0 Wire.write(0xFF); // Register 12 / Group duty cycle control Wire.write(0x00); // Register 13 / Group frequency Wire.write(0xAA); // Register 14 / LED output state 0 // Default alle LEDs auf PWM Wire.write(0xAA); // Register 15 / LED output state 1 // Default alle LEDs auf PWM Wire.write(0xAA); // Register 16 / LED output state 2 // Default alle LEDs auf PWM Wire.write(0xAA); // Register 17 / LED output state 3 // Default alle LEDs auf PWM Wire.write(0x00); // Register 18 / I2C bus subaddress 1 Wire.write(0x00); // Register 19 / I2C bus subaddress 2 Wire.write(0x00); // Register 1A / I2C bus subaddress 3 Wire.write(0x00); // Register 1B / All Call I2C bus address Wire.write(0xFF); // Register 1C / IREF configuration Wire.endTransmission(); // I2C-Stop } // Diese Funktion setzt die Helligkeit für ein LED-Register // Voraussetzung ist, das im entsprechende Register 14 bis 17 die LED aktiviert ist // Übergabeparameter: LED = Nummer der LED / PWM = Helligkeitswert 0 -255 void Set_LED_PWM(int LED, int PWM) { Wire.begin(); //I2C-Start Wire.beginTransmission(B1100000); // TLC59116 Slave Adresse ->C0 hex Wire.write(0x01 + LED); // Register LED-Nr Wire.write(PWM); Wire.endTransmission(); // I2C-Stop BRIGHTNESS_Array[LED] = PWM; } // Diese Funktion setzt die Helligkeit für alle LED-Register gleichzeitig // Voraussetzung ist, das im entsprechende Register 14 bis 17 die LED aktiviert ist // Übergabeparameter: PWM = Helligkeitswert 0 -255 void Set_LED_ALL(int PWM) { Wire.begin(); // I2C-Start Wire.beginTransmission(B1100000); // TLC59116 Slave Adresse ->C0 hex Wire.write(0x82); // Startregister 02h for (int i=1 ; i < 17; i++){ // 16Bytes (Register 02h bis 11h) schreiben Wire.write(PWM); BRIGHTNESS_Array[i] = PWM; } Wire.endTransmission(); // I2C-Stop } void send_LED_ALL_Array() { BRIGHTNESS_string = "{\"LEDpwm\": [\""+ String(BRIGHTNESS_Array[1]) ; for (int i=2 ; i < 17; i++){ BRIGHTNESS_string += "\", \""+ String(BRIGHTNESS_Array[i]); } BRIGHTNESS_string += "\"]}"; //Serial.println(BRIGHTNESS_string); } //////////////////////////// TLC59116 WLAN ///////////////////////////////// void handleLED_switch_fkt(int arg1) { if (BRIGHTNESS_Array[arg1] > 127) BRIGHTNESS_Array[arg1] = 0; else if (BRIGHTNESS_Array[arg1] < 128) BRIGHTNESS_Array[arg1] = 255; Set_LED_PWM(arg1,BRIGHTNESS_Array[arg1]); Serial.print(arg1); Serial.println(" done\n"); }
Die Weboberfläche (index.html)
Die html Datei steuert über onclick javascript events (XMLHttpRequest) die LEDs und bekommt den aktuellen PWM Wert zurückgemeldet.
<!DOCTYPE html> <html> <title>LED Info</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> rect:hover { fill: white; opacity:0.5; } rect { fill: white; stroke-width:8; opacity:0.2; } </style> <body > [ <a href="./upload">Upload</a> ] [ <a onclick="getLEDswitch()">LED (an/aus)</a> ] [ <a href="./wifi">WIFI</a> ] [ <a href="./i2c">I2C status</a> ] <hr> <figure id="imageMapRoom"> <svg viewBox="0 0 462 286" > <defs> <style> rect { fill:white; stroke:grey; stroke-width:5; fill-opacity:0.1; stroke-opacity:0.9 } rect:hover { fill: white; opacity:0.8; } </style> </defs> <image id="imageMapRoomPic" width="462" height="286" xlink:href="./img/living_room_demo.png" > <title>Living Room LEDs</title> </image> <a onclick="UpdateTab(1)" > <rect id="Feld_LED_K1" x="10" y="10" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(2)"> <rect id="Feld_LED_K2" x="70" y="10" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(3)"> <rect id="Feld_LED_K3" x="130" y="10" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(4)"> <rect id="Feld_LED_K4" x="190" y="10" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(5)"> <rect id="Feld_LED_K5" x="10" y="70" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(6)"> <rect id="Feld_LED_K6" x="70" y="70" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(7)"> <rect id="Feld_LED_K7" x="130" y="70" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(8)"> <rect id="Feld_LED_K8" x="190" y="70" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(9)"> <rect id="Feld_LED_K9" x="10" y="130" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(10)"> <rect id="Feld_LED_K10" x="70" y="130" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(11)"> <rect id="Feld_LED_K11" x="130" y="130" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(12)"> <rect id="Feld_LED_K12" x="190" y="130" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(13)"> <rect id="Feld_LED_K13" x="10" y="190" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(14)"> <rect id="Feld_LED_K14" x="70" y="190" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(15)"> <rect id="Feld_LED_K15" x="130" y="190" width="50" height="50" rx="20" ry="20" /> </a> <a onclick="UpdateTab(16)"> <rect id="Feld_LED_K16" x="190" y="190" width="50" height="50" rx="20" ry="20" /> </a> </svg> <figcaption> auf die Felder klicken ...</figcaption> </figure> <script> getData(); function getLEDswitch(){ //"href="./LEDswitch?position=" var xhttp = new XMLHttpRequest(); xhttp.open("GET", "./LEDswitch" , true); //Handle readADC server on ESP8266 xhttp.send(); getData(); } function UpdateTab(LEDnr) { // onClick= "UpdateTab(1);" var xhttp = new XMLHttpRequest(); xhttp.open("GET", "./LEDswitch?LED=" + LEDnr, true); //Handle LED on ESP8266 server xhttp.send(); getData(); } //tutorial: <a href="https://www.w3schools.com/js/js_json_parse.asp"> https://www.w3schools.com/js/js_json_parse.asp </a> // {"LEDpwm": ["0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"]} function getData() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { //Push the data in array var txt = this.responseText; var obj = JSON.parse(txt); var txtID = ""; var feldID = ""; for (var i=1;i<17;i++){ feldID = "Feld_LED_K" + i; if ( parseInt(obj["LEDpwm"][i-1]) > 10 ) document.getElementById(feldID).style.stroke = "rgb(0,"+ parseInt(obj["LEDpwm"][i-1]) +",0)"; else document.getElementById(feldID).style.stroke = "red"; } } }; xhttp.open("GET", "./readLED", true); //Handle readLED server on ESP8266 xhttp.send(); } </script> </body> </html>
Weboberfläche
Die Veränderungen der LED PWM werden in der
Weboberfläche über onclick="UpdateTab(xx)" Aufrufe gesteuert. Diese ruft auf dem ESP Server die URL ./LEDswitch?LED=LEDnr auf und toggelt die jeweilige LEDnr. Die Aktualisierung aller LED PWMs Rückmeldungen in der Weboberfläche übernimmt getData().
.
- Sektch hochladen
- ./upload aufrufen und die index.html Datei hochladen (SPIFFS)
-
./upload aufrufen und die living_room_demo.png Datei hochladen (SPIFFS)
.
Einen eigenen Plan kann man sehr einfach unter https://floorplanner.com erstellen.
und nun viel Spaß beim Nachbauen