Christos Meletis
Published © GPL3+

The Ring

The one ring to outglow them all! Hehe. Its a nice wall mounted light painting with textured mountains and grass.

AdvancedShowcase (no instructions)Over 4 days12
The Ring

Things used in this project

Hardware components

WLED or Cold/Warm LED controller
I used a controller of my own creation for this project, but any controller like the Gledopto should be able to acomplish basic usage of this project.
×1
LED Strip, 5 m
LED Strip, 5 m
×1

Story

Read more

Schematics

ESP LED strip touch controller

A simple ESP8266 controller with embedded touch chip to controll 12V Led strips Unforturantely the original files are missing, but you could use the gerbers.

Code

The Ring Code

C/C++
Simple Arduino sketch to get values from 2 sliding bars and control the intencity of the led strips.
 /*********
  Author:Christos Meletis
  This is a test to prevent me from being softlock out of my systems.

  TODO
  -Create softAP if connection to wifi fails.  ------------------[DONE]
  -Add strong password in STA_PASS variable for softAP. ---------[DONE]
  -Create simple html form to get new credentials from user.  ---[DONE]
  -Store new credentials to EEPROM  -----------------------------[DONE]
  -Retreve credentials from EEPROM  -----------------------------[DONE]
  -Set a ticker for rollback  -----------------------------------[DONE]
  -Clean Code and add comments
*********/
//___________________________________________________________________________________________________
// -------------- Libraries -------------- 
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ArduinoOTA.h>
#include <Ticker.h>
#include <EEPROM.h>
#include "html(update_wifi_credentials).h"
#include "html(dark_blue).h"

// -------------- Variable declarations --------------
// -------------- Wifi Related --------------

#define DEVNAME "ChrIndustries_Ring";
#define APPSWD "1234567890";

#define SSID_SZ 32        //length of ssid
#define PASSWORD_SZ 128   //length of password

//ssid and password declarations (STA)
//const char* STA_SSID = "NASA2018"; //"NatassaChrisWLAN";
//const char* STA_PASS = "fvis2018"; //"z5gQ4Q9TAz7EQK6r";
char STA_SSID[SSID_SZ];
char STA_PASS[PASSWORD_SZ];
int STA_ADDR_SUBNET = 2;      //subnet IP field [xxx.xxx.???.xxx]
int STA_ADDR_HOST = 200;      //host device [fourth] IP field [xxx.xxx.xxx.???]
#define OTA_PASS "C#r1nDu$+r13s"

//ssid and password declarations (SAP)
const char *AP_SSID = DEVNAME;
const char *AP_PASS = APPSWD;
boolean AP_ENABLE = false;


//StaticIP address configuration (for STA)
IPAddress staticIP(192, 168, 2, 200); //ESP static ip
IPAddress gateway(192, 168, 2, 1);   //IP Address of your WiFi Router (Gateway)
IPAddress subnet(255, 255, 255, 0);  //Subnet mask
IPAddress dns(8, 8, 8, 8);  //DNS

const char* DEVICE_NAME = DEVNAME;

// Create WiFiServer object on port 80
ESP8266WebServer server(80);

//Ticker to enable AP mode after 1 minute (if not connected to any WiFi)
Ticker WiFi_EnableAP_timeout;
//Ticker for system restart after 3 minutes (if not connected to any WiFi)
Ticker WiFi_RetryNoClient_restart;
//create a ticker objec, for timekeeping
Ticker TimeKeeper;          

//---------------Morphing Light Variables--------------
#define OUT_LED_WARM D1  //variable to controll the warm leds
#define OUT_LED_COLD D8  //variable to controll the cold leds
#define ENABLE D2   //variable to interface touch panel

String SLIDER_VALUE = "0";           //variable to store the HTML values of slider
const char* PARAM_INPUT = "value";  //donno what this is
uint16_t AMP_WARM = 0;              //actual value for warm LED brightness
uint16_t AMP_COLD = 0;	            //actual value for cold LED brightness
bool LED_STATUS = 0;                 //status of light "on-off" mostly used for logic, and various function handling


//___________________________________________________________________________________________________

// -------------- Functions --------------
void epprom_write_wifi_credentials ( char* STA_SSID, char* STA_PASS, int STA_ADDR_SUBNET, int STA_ADDR_HOST);
void epprom_read_wifi_credentials (void);
void rollback(void);

void handle_root(void);
void handle_update_wifi_credentials(void);
void handle_pwm(void) ;

void IncAmpWarm(void);
void IncAmpCold(void);
void LightON(void);



// -------------- Initialization --------------
void setup(){

  //Set IO pins
  pinMode(ENABLE, INPUT);     //Pin D1 interfaces a capacitive touch sensor.
  pinMode(OUT_LED_WARM, OUTPUT);   //Pin D2 interfaces the MOSFET of the warm LED strip
  pinMode(OUT_LED_COLD, OUTPUT);   //Pin D8 interfaces the second MOSFET for the cold LED strip
  analogWrite(OUT_LED_WARM, 0);    //[Set output to 0V]
  analogWrite(OUT_LED_COLD, 0);    //[Set output to 0V]
  
  // Configure EEPROM
  EEPROM.begin(255);  
  
  Serial.begin(115200);                   //start serial for debugging  
  Serial.println("Initializing I/O");     //-----LOG 


  // Read WiFi credentials from EEPROM
  epprom_read_wifi_credentials();

  // If STA_SSID and password were read successfully from EEPROM attempt to connect to to WiFi
  if ( strlen(STA_SSID) > 0 && strlen(STA_PASS) > 0 ) {
  
    Serial.println("Starting Station");         //-----LOG
    WiFi.disconnect();                          //Prevent connecting to wifi based on previous configuration
    WiFi.hostname(DEVICE_NAME);                 // DHCP Hostname (useful for finding device for static lease)

    if(STA_ADDR_SUBNET >= 1 && STA_ADDR_SUBNET <= 254 && STA_ADDR_HOST >= 2 && STA_ADDR_HOST <= 254){
    //set up staticIP for configuration
      staticIP[2] = STA_ADDR_SUBNET;                    //set device IP subnet number
      staticIP[3] = STA_ADDR_HOST;                      //set device IP host number
      gateway[2] = STA_ADDR_SUBNET;                     //set gateway IP subnet number  
    }

    if(!WiFi.config(staticIP, gateway, subnet, dns )){//try configuring WiFi
     Serial.println("STA failed config");     //-----LOG
    }

    WiFi.mode(WIFI_STA);                      //WiFi mode station (connect to wifi router only)
    WiFi.begin(STA_SSID, STA_PASS);           //Connect to Router

    Serial.println("Setting up timeouts.");   //-----LOG
    //if WiFi cannot connect then Rollback to AP mode after 2 minutes
    
    //enable AP mode if not connectet to any WiFi after 1 minute
    WiFi_EnableAP_timeout.once(60, rollback);  
    //system restart after 3 minutes
    WiFi_RetryNoClient_restart.once(180, ESP.restart);
    
    Serial.print("Connecting to WiFi");  //-----LOG
    while (WiFi.waitForConnectResult() != WL_CONNECTED) { // Switch to AP mode if unable to connect
      Serial.print(".");
      delay(5000);
      if(AP_ENABLE)break; 
    }
  }
  else{ //If there are no saved credentials, then enter AP mode
    Serial.println("No network credentials. Switching to Access Point mode.");//-----LOG
    rollback(); //enter AP mode
  }

  if(!AP_ENABLE){
    Serial.println("");                   //-----LOG
    Serial.print("Connected to ");        //-----LOG
    Serial.println(STA_SSID);             //-----LOG
    Serial.print("IP address: ");         //-----LOG
    Serial.println(WiFi.localIP());       // IP address given to NodeMCU //-----LOG
    WiFi_EnableAP_timeout.detach();
    WiFi_RetryNoClient_restart.detach();
  }
  
  server.on("/", handle_root);            // primary page where html from .h file will be shown
  server.on("/update", handle_update_wifi_credentials);       // handles the PWM values
  server.on("/setPWM", handle_pwm);       // handles the PWM values  
 
  
  server.begin();                         // Start server
  Serial.println("HTTP server started");  //-----LOG


/*--------------------------------------- OTA ---------------------------------------*/
  // Port defaults to 8266
  // ArduinoOTA.setPort(8266);  
  ArduinoOTA.setHostname(DEVICE_NAME);// Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setPassword(OTA_PASS);        // No authentication by default

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_FS
      type = "filesystem";
    }

    // NOTE: if updating FS this would be the place to unmount FS using FS.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("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();
  Serial.println("OTA ENABLED");

/*---------------------------------------OTA END---------------------------------------*/  
}
  
void loop() {

  ArduinoOTA.handle();        //for OTA programming
  server.handleClient();      //handle incomming requests on WiFi page
  
  if(digitalRead(ENABLE)){
    delay(50); //bouncing, touch false triggering
    if(digitalRead(ENABLE)){      //button or sensor press
        delay(500);             //wait for buton depress

        if(!digitalRead(ENABLE)){//if button is depressed
          if(!LED_STATUS){       //if the light was dimmed too low or off, switch intensity to half
            //set brightness to ~25%
			AMP_WARM = 64;
			AMP_COLD = 64;
            LED_STATUS = 1;    
          }
          else{				//if the light was on, then turn intensity to 0
            //set brightness to 0%
			AMP_WARM = 0;
			AMP_COLD = 0;
            LED_STATUS = 0;        
          }
        }    
      
        while(digitalRead(ENABLE)){  //if sensor is still pressed then increase luminocity gradually      
          if(AMP_WARM<255 || AMP_COLD<255){
            IncAmpWarm(); //Increase Led AMP_WARM-litude every 10ms
			IncAmpCold(); //Increase Led AMP_COLD-litude every 10ms
          }
          LED_STATUS=1;          
          delay(10);  //delay each increment to give user time to decide on wanted brightness
          LightON();      //Switch the light to the according intensity
        }
    
      Serial.print("Touch Triggered. ");    //-----LOG
      Serial.print("LED_STATUS: ");          //-----LOG
      Serial.println(LED_STATUS);            //-----LOG
      }
  }

  LightON();      //Switch the light to the according intensity      
 
}



/* handle_root()
 * prints out main page with pwm slider
 */
void handle_root() {Serial.print("/root");    //-----LOG
 String root_code = html_page;              // html code from .h file
 server.send(200, "text/html", root_code);  // upload code to show webpage
}

/* handle_update_wifi_credentials
   function that updates the wifi credentials as well as the last 2 fields of the IP address
   This function server the client a simple html page and asks for wifi SSID and Password
   User submits the credentials and the programm stores the new values into its eeprom
   After writing the new credentials the system restarts
*/
void handle_update_wifi_credentials(){
  WiFi_RetryNoClient_restart.detach();
  
  String update_code = html_update_wifi_credentials;            //html from html(update_wifi_credentials).h file
  server.send(200, "text/html", html_update_wifi_credentials);  // upload code to show webpage

  if(server.hasArg("NEW_SSID") && server.hasArg("NEW_PASS")){
    String NEW_SSID = server.arg("NEW_SSID");                 //fetch new network name from web page
    String NEW_PASS = server.arg("NEW_PASS");                 //fetch new network password from web page
    String NEW_ADDR_SUBNET = server.arg("NEW_ADDR_SUBNET");   //fetch new network subnet number from web page
    String NEW_ADDR_HOST = server.arg("NEW_ADDR_HOST");       //fetch new network host number from web page
    STA_ADDR_SUBNET = NEW_ADDR_SUBNET.toInt();                    //set device IP subnet number
    STA_ADDR_HOST = NEW_ADDR_HOST.toInt();                      //set device IP host number
      
    for(uint16_t i=0 ; i<= NEW_SSID.length() ; i++){
      STA_SSID[i] = NEW_SSID[i];
    }

    for(uint16_t i=0 ; i<= NEW_PASS.length() ; i++){
      STA_PASS[i] = NEW_PASS[i];
    }

    epprom_write_wifi_credentials (STA_SSID,STA_PASS,STA_ADDR_SUBNET,STA_ADDR_HOST);
    Serial.println("WiFi Credentials updated.");      //-----LOG
    Serial.println("Restarting system.");    
    ESP.restart();
  }
}

/* handle_pwm()
 * Changes the AMP_WARM variable according to changes in the webserver site
 */
void handle_pwm() {Serial.print("/pwm");    		//-----LOG
 String warm_pwm_val = server.arg("WarmSliderVal");	// reading from slider on html page
 AMP_WARM = warm_pwm_val.toInt();                   // chaning the value on the NodeMCU board
 String cold_pwm_val = server.arg("ColdSliderVal");	// reading from slider on html page
 AMP_COLD = cold_pwm_val.toInt();                   // chaning the value on the NodeMCU board
 server.send(200,"text/plane","0");       			// handling the webpage update

    Serial.print("WiFi Triggered. ");			//-----LOG
    Serial.print("Warm brightness set to: ");	//-----LOG
    Serial.print(AMP_WARM);						//-----LOG
    Serial.print("Cold brightness set to: ");	//-----LOG
    Serial.print(AMP_COLD);						//-----LOG
    Serial.print("LED_STATUS: ");           	//-----LOG
    Serial.println(LED_STATUS);             	//-----LOG
 
}

/*  IncAmpWarm
 *  Increases the AMP_WARM variable in steps of 5
 *  This Function mostly gives programmer mobility, ex: can increase or decrease step by user request
 */
void IncAmpWarm(void){
  AMP_WARM += 5;
}

/*  IncAmpCold
 *  Increases the AMP_COLD variable in steps of 5
 *  This Function mostly gives programmer mobility, ex: can increase or decrease step by user request
 */
void IncAmpCold(void){
  AMP_COLD += 5;
}

/*  LightON
 *  Function to set the PWM output based on the AMP_WARM variable
 */
void LightON(void){
  analogWrite(OUT_LED_WARM, AMP_WARM);
  analogWrite(OUT_LED_COLD, AMP_COLD);
}

/* rollback()
 *  Function to set ESP as an Access Point.
 *  The function is called in case the system fails to connect to any network
 */
void rollback(){    //default softAP IP is 192.168.4.1
  WiFi_EnableAP_timeout.detach();                    //prevent system from re-rolling back
  WiFi.mode(WIFI_AP);                       //WiFi mode Access Point
  Serial.println("Configuring access point...");

  WiFi.softAPConfig(gateway, gateway, subnet);   //Set SoftAP Ip,Gateway,Subnet

  //Start the SoftAP, but also check if it started properly with boolean AP_ENABLE
  AP_ENABLE = WiFi.softAP(AP_SSID,AP_PASS);  

  Serial.print("AP IP address: ");          //-----LOG
  Serial.println(WiFi.softAPIP());          //-----LOG
}

/* Writes the Wifi SSID, password the IP subnet, host to EEPROM
 */
void epprom_write_wifi_credentials ( char* STA_SSID, char* STA_PASS, int STA_ADDR_SUBNET, int STA_ADDR_HOST) {
  
  int offset;
  
  // Write SSID length to EEPROM
  offset = 0;
  EEPROM.write(offset++, (byte) strlen(STA_SSID));

  // Write SSID to EEPROM
  for ( int i = 0; STA_SSID[i] != '\0' && i < SSID_SZ; ++i ) {
    EEPROM.write(offset + i, STA_SSID[i]);
  }

  // Write password length to EEPROM
  offset += strlen(STA_SSID);
  EEPROM.write(offset++, (byte) strlen(STA_PASS));

  // Write password to EEPROM
  for ( int i = 0; STA_PASS[i] != '\0' && i < PASSWORD_SZ; ++i ) {
    EEPROM.write(offset + i, STA_PASS[i]);
  }
  
  EEPROM.put(200, STA_ADDR_SUBNET); // Write subnet to EEPROM
  EEPROM.put(210, STA_ADDR_HOST);   // Write host to EEPROM
  
  EEPROM.commit();                  // Write changes to EEPROM
      
}

/* Reads the Wifi SSID, password and IP subnet, host fields from EEPROM
 */
void epprom_read_wifi_credentials () {
  
  int variableLength = 0;
  int offset;

  STA_SSID[0] = '\0';
  STA_PASS[0] = '\0';
  
  // Read SSID from EEPROM
  offset = 0;
  variableLength = (int) EEPROM.read(offset++);

  if ( variableLength > 0 ) {
    int i;    
    for ( i = 0; i < variableLength && i < SSID_SZ; ++i ) {
      STA_SSID[i] = (char) EEPROM.read(offset+i);  
    }
    STA_SSID[i] = '\0';    
  }

  // Read password from EEPROM
  offset += variableLength;
  variableLength = (int) EEPROM.read(offset++);
  
  if ( variableLength > 0 ) {   
    int i;    
    for ( i = 0; i < variableLength && i < PASSWORD_SZ; ++i ) {
      STA_PASS[i] = (char) EEPROM.read(offset+i); 
    }    
    STA_PASS[i] = '\0';    
  }
  
  EEPROM.get(200, STA_ADDR_SUBNET); // Read subnet from EEPROM
  EEPROM.get(210, STA_ADDR_HOST);   // Read host from EEPROM
  
}

//------------------- END OF CODE -------------------

VScode PlatformIO project

Full code for the project based on my custom made ESP led strip controller.

Credits

Christos Meletis
6 projects • 1 follower
It all started building an FM receiver with grandpa. Turned bedroom to lab, now half a house, maybe Dexter's lab next?

Comments