EPS8266 WEB LED Control + PWM + UI + Reboot

Introduction: EPS8266 WEB LED Control + PWM + UI + Reboot

About: esp8266 projects

Im dritten Teil können nun alle LEDs individuell über Slider gedimmt werden. Die Rückmeldung erfolgt wieder über den Raumplan jetzt aber mit einer genauen Farbveränderung passend zu dem PWM Wert in den Feldern und über die 16 Slider (mit Werten).

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 hatte 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.

Step 1: Erwiterungen in CaptivePortalAdvanced.ino

+ server.on("/LEDpwm", handleLED_pwm);

+ server.on("/reboot", handleReboot);

#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  http://192.168.4.1/wifi  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  http://192.168.4.1/wifi  (the IP you took note of) or maybe at  http://192.168.4.1/wifi  too.

   This is a captive portal because through the softAP it will redirect any http request to  http://192.168.4.1/wifi 
*/

//////////////////////////// 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  http://192.168.4.1/wifi  */
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 + LED PWM*/ 
  server.on("/readLED", handleStatusLED);
  server.on("/LEDswitch", handleLED_switch);
  server.on("/LEDpwm", handleLED_pwm);
    
  /* Setup web pages: I2C info on COM port */
  server.on("/i2c", handleStatusI2C);

  /* Setup web pages: Reboot ESP*/
  server.on("/reboot", handleReboot);

      
  /* 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();
}

Step 2: 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();
}

Step 3: Erwiterungen in HandleHttp.ino

+ handleLED_pwm()

/** 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 PWM link and redirect to WLAN root page again */
void handleLED_pwm() {
  BLINKPIN_ON();
  // ./LEDpwm?LED=xx&PWM=yy  
  
    int arg1 = 0; 
    int arg2 = 0;    
    arg1 =  server.arg(0).toInt();
    arg2 =  server.arg(1).toInt();
    
    if (server.args() > 1){ // LEDnr and PWM OK?            
      BRIGHTNESS_Array[arg1] = arg2;
      Set_LED_PWM(arg1, arg2);

      send_LED_ALL_Array();

    }
    
   server.sendHeader("Location", "/",true);   //redirect to WLAN root page
   server.send(302, "text/plane",""); 
  
  BLINKPIN_OFF();
}


/** Handle the WLAN LED link and redirect to WLAN root page again */
void handleLED_switch() {
BLINKPIN_ON();
 // ./LEDswitch?LED=xx
 //   server.argName(i) => server.arg(i)  
    int arg1 = 0;    

    if (server.args() > 0){ // LEDnr OK? 
    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","");     
}

/** Handle the WLAN Reboot link and redirect to WLAN root page again */
void handleReboot(){
    Serial.println("Rebooting...");
    Serial.flush(); // end output on serial 

   server.sendHeader("Location", "/",true);   //redirect to WLAN root page
   server.send(302, "text/plane","");     
   delay(1000);
   ESP.restart();  // start reset ESP
}

Step 4: Erwiterungen in Tools.ino

+ Set_LED_PWM(int LED, int PWM)

/** 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");           
}

Step 5: Die Weboberfläche (index.html)

Durch verschieden Erweiterung in der Weboberfläche und der ESP Programmierung können nun alle einzelnen LED PWM Werte verändert und angezeigt werden. In der Zweien Version der Weboberfläche wurde nur zwischen ein- bzw. ausgeschaltet unterschieden. Jetzt können einzelne LEDs über den Plan geschaltet oder über die 16 Slider gedimmt werden.

<!DOCTYPE html>
<html>
<title>LED Info</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Cache-control" content="no-store">
<meta http-equiv="expires" content="-1">

<style>

	rect {  
		fill:white;
		stroke:grey;
		stroke-width:5;
		fill-opacity:0.1;
		stroke-opacity:0.9
	  }

    rect:hover {
	    fill: white;
	    opacity:0.2;
	  }

/* Basics & Browser Support, Grids, Headings http://mincss.com */

	body,textarea,input,select{background:0;border-radius:0;font:16px sans-serif;margin:0}
	.addon,.btn-sm,.nav,textarea,input,select{outline:0;font-size:14px}
	.smooth{transition:all .2s}
	.btn,.nav a{text-decoration:none}
/*  .container{margin:0 20px;width:auto}@media(min-width:1310px){
		.container{margin:auto;width:1270px}}
	*/
	
	h2{font-size:2em}	
	h1{font-size:3em; margin: 0.2em 0; margin-bottom: 0.2em; border-bottom: 5px solid; margin-bottom: 15px; padding-bottom: 5px;}
	
	.row{margin:1% 0;overflow:auto}
	.col{float:left}
	.table,.c12{width:100%}
	.c11{width:91.66%}
	.c10{width:83.33%}
	.c9{width:75%}
	.c8{width:66.66%}
	.c7{width:58.33%}
	.c6{width:50%}
	.c5{width:41.66%}
	.c4{width:33.33%}
	.c3{width:25%}
	.c2{width:16.66%}
	.c1{width:8.33%}
	
	@media(max-width:870px){.row .col{width:100%}}


/*tutorial @ http://twiggle-web-design.com/tutorials/Custom-Vertical-Input-Range-CSS3.html */

.container { border: 3px solid #eee; margin: 10px; padding:10px; float:left; text-align: center; max-width: 25%;}

/*customised range*/ 
input[type="range"].range
{
     cursor: pointer;
     width: 100px !important;
     -webkit-appearance: none;
     z-index: 200;
     width:50px;
     border: 1px solid #e6e6e6;
     background-color: #e6e6e6;
     background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#e6e6e6), to(#d2d2d2));
     background-image: -webkit-linear-gradient(right, #e6e6e6, #d2d2d2);
     background-image: -moz-linear-gradient(right, #e6e6e6, #d2d2d2);
     background-image: -ms-linear-gradient(right, #e6e6e6, #d2d2d2);
     background-image: -o-linear-gradient(right, #e6e6e6, #d2d2d2);
}

/*customised range when focusing on input */ 
input[type="range"].range:focus
{
     border: 0 !imporant;
	outline: none !important;
}

/*customised range slider icon*/ input[type="range"]
.range::-webkit-slider-thumb
{
     -webkit-appearance: none;
     width: 10px;
     height: 10px;
	 background-color: #555;
     background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#4DDBFF), to(#00CCFF));
     background-image: -webkit-linear-gradient(right, #4DDBFF, #00CCFF);
     background-image: -moz-linear-gradient(right, #4DDBFF, #00CCFF);
     background-image: -ms-linear-gradient(right, #4DDBFF, #00CCFF);
     background-image: -o-linear-gradient(right, #4DDBFF, #00CCFF);
}

/*setting round corners to the range */ 
input[type="range"].round {
     -webkit-border-radius: 20px;
     -moz-border-radius: 20px;
     border-radius: 20px;
}

/*setting round corners to the range slider icon*/ 
input[type="range"].round::-webkit-slider-thumb {
    -webkit-border-radius: 5px;
	-moz-border-radius: 5px;
	-o-border-radius: 5px;
}

/* set range from 1 - 0 vertically (highest on top) */ 
.vhf /*.vertical-heighest-first */
{
     -webkit-transform:rotate(270deg);
     -moz-transform:rotate(270deg);
     -o-transform:rotate(270deg);
     -ms-transform:rotate(270deg);
     transform:rotate(270deg); 
}
	 

</style>
<body >
    [ <a href="./upload">Upload</a> ]
	[ <a onclick="LEDswitch()">LED (an/aus)</a> ]
	[ <a href="./wifi">WIFI</a> ]	
	[ <a href="./i2c">I2C status</a> ]	
	[ <a href="./reboot">reboot ESP</a> ]		
 <hr>
 
 <div class="row">
    <div class="col c12"><h1>Map</h1></div>

	<div class="col c12">		
<figure id="imageMapRoom">
<svg viewBox="0 0 462 286" width="462" height="286">
  <image id="imageMapRoomPic" width="462" height="286" xlink:href="./img/living_room_demo.png" >
    <title>Living Room LEDs</title>
  </image>	
  
  <a onclick="UpdateLED(1)" >
    <rect id="Feld_LED_K1" x="20" y="20"  width="50" height="50"  rx="20" ry="20" />
  </a>
   <a onclick="UpdateLED(2)">
    <rect id="Feld_LED_K2" x="80" y="20"  width="50" height="50"  rx="20" ry="20" />
  </a>
   <a onclick="UpdateLED(3)">
	<rect id="Feld_LED_K3" x="140" y="20"  width="50" height="50" rx="20" ry="20" />
  </a>
  <a onclick="UpdateLED(4)">
	<rect id="Feld_LED_K4" x="200" y="20"  width="50" height="50" rx="20" ry="20" />
  </a>
  
  <a onclick="UpdateLED(5)">
	<rect id="Feld_LED_K5" x="20" y="80"  width="50" height="50" rx="20" ry="20" />
  </a>
    <a onclick="UpdateLED(6)">
	<rect id="Feld_LED_K6" x="70" y="80"  width="50" height="50" rx="20" ry="20" />
  </a>
  <a onclick="UpdateLED(7)">
	<rect id="Feld_LED_K7" x="140" y="80"  width="50" height="50" rx="20" ry="20" />
  </a>
    <a onclick="UpdateLED(8)">
	<rect id="Feld_LED_K8" x="200" y="80"  width="50" height="50" rx="20" ry="20" />
  </a>
  
  <a onclick="UpdateLED(9)">
	<rect id="Feld_LED_K9" x="20" y="140"  width="50" height="50" rx="20" ry="20" />
  </a>
    <a onclick="UpdateLED(10)">
	<rect id="Feld_LED_K10" x="80" y="140"  width="50" height="50" rx="20" ry="20" />
  </a>
  <a onclick="UpdateLED(11)">
	<rect id="Feld_LED_K11" x="140" y="140"  width="50" height="50" rx="20" ry="20" />
  </a>
    <a onclick="UpdateLED(12)">
	<rect id="Feld_LED_K12" x="200" y="140"  width="50" height="50" rx="20" ry="20" />
  </a>
  
    <a onclick="UpdateLED(13)">
	<rect id="Feld_LED_K13" x="20" y="200"  width="50" height="50" rx="20" ry="20" />
  </a>
    <a onclick="UpdateLED(14)">
	<rect id="Feld_LED_K14" x="80" y="200"  width="50" height="50" rx="20" ry="20" />
  </a>
  <a onclick="UpdateLED(15)">
	<rect id="Feld_LED_K15" x="140" y="200"  width="50" height="50" rx="20" ry="20" />
  </a>
    <a onclick="UpdateLED(16)">
	<rect id="Feld_LED_K16" x="200" y="200"  width="50" height="50" rx="20" ry="20" />
  </a> 
</svg>
  <figcaption> auf die Felder klicken ...</figcaption>
</figure>		
		</div>
	</div>
		
<div class="row">
	<div class="col c12"><h1>Slider</h1></div>	
</div>	

<div class="row" id="sliderHTML">
</div>  


	
<script> 
//////////////////////////////////////////////////////

// silder container
	var txtHTML = "";

    for (var i=1;i<17;i++) {
	txtHTML += "<div class=\"container\" style=margin-right: 0px><span>";
	txtHTML += i ;
    txtHTML += "</span><br><br><br><br><input id=\"LEDsilder";
	txtHTML += i ;	
	txtHTML += "\" oninput=\"UpdateLEDdim(";
	txtHTML += i ;
	txtHTML += ",this.value)\" ";
	txtHTML += " type=\"range\" class=\"range vhf round\" min=\"0\" max=\"255\" step=\"1\">";
	txtHTML += " <br><br><br><br><span id=\"wertLED_K";
	txtHTML += i ;	
	txtHTML += "\">000</span></div>";
    }
 
    document.getElementById("sliderHTML").innerHTML = txtHTML;


  
function LEDswitch(){  // onClick= "UpdateLEDdim();"
  var xhttp = new XMLHttpRequest();
  xhttp.open("GET", "./LEDswitch" , true); //Handle LED on/off ESP8266 server
  xhttp.send();
  getData();
}

function UpdateLED(LEDnr) {  // onClick= "UpdateLED(xx);" 
  var xhttp = new XMLHttpRequest();
  xhttp.open("GET", "./LEDswitch?LED=" + LEDnr, true); //Handle LED on/off on ESP8266 server
  xhttp.send();
  getData();
}

function UpdateLEDdim(LEDnr,LEDpwm) {  // onClick= "UpdateLEDdim(xx,yyy);"
  var xhttp = new XMLHttpRequest();
  xhttp.open("GET", "./LEDpwm?LED=" + LEDnr + "&PWM=" + LEDpwm, true); //Handle LED PWM on ESP8266 server
  xhttp.send();
  getData();
}

//tutorial: https://www.w3schools.com/js/js_json_parse.asp 
// {"LEDpwm": ["32", "32", "32", "32", "32", "32", "32", "32", "32", "32", "32", "32", "32", "32", "32", "32"]}
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 objID = "";
  var feldID = "";
   
		for (var i=1;i<17;i++){
			 txtID = "wertLED_K"  + i; 
			 objID = "LEDsilder"  + i;
			feldID = "Feld_LED_K" + i;
		
			document.getElementById(txtID).innerHTML = obj["LEDpwm"][i-1]; 
			document.getElementById(objID).value = obj["LEDpwm"][i-1];
		
		if ( parseInt(obj["LEDpwm"][i-1]) > 48 )    
			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 on ESP8266 server
  xhttp.send();
}

 //////////////////////////////////////////////////////
	getData();
	
</script>

</body>
</html>

Be the First to Share

    Recommendations

    • Micro:bit Contest

      Micro:bit Contest
    • Halloween Contest

      Halloween Contest
    • Soup & Stew Speed Challenge

      Soup & Stew Speed Challenge

    Comments