Monday, November 27, 2017

WEMOS wifi manager.

WEMOS or ESP8622v12 switch

This project is simple upload and switch stuff on and off over your own wifi network. Switching is limited to your own personal choice. WEMOD D1 have 9 pins you can use as switches. Yes there are many code doing that. 
Why use this one code. 
To start with, you dont have to hard code password and settings. Recompile if something change. It is all handled by access point mode.
With new ESP if will write default settings once to EEPROM. Then restart again into access point mode for you to select you access point you want to connect to. Setup your password. Then you restart it. 
If your details were correctly entered, you will be connected to your network. 
Now you in client mode where you click buttons to switch stuff on. 
Second
This is the full version. 2 modes access point and client mode. 
Proses the data you received. Even rwplace special characters with really characters. 
Get and Set EEPROM. SAVING LONG STRING VALUES. 
Lots off fun to get to know the code. I added comments to about everything. 

Software 
Arduino IDE with ESP8622 libraries installed. 
Look at this tutorial Esp8266 to install all you need. I see no point copying his work and add it to my work. 

What you will need:
1 x WEMOS D1 mini or ESP8622-01 or 12 WEMOS is just easier. 

1 x 8 port relay or smaller
1 x 12 volt power supply 

Lots of some  colorful wires to hook up WEMOS to you relay module. 

Intro:
This is fully working wi-fi switch. By using relay to switch on stuff over you network using the WEMOS. But it will work on ESP-v12 and ESP-v1. With some small changes. Like pin outs. 

This is just my code. I did use lots of other people work to finish this project. Wish I remembered all of them for credits. Most is the examples that came with esp libraries, just mixed into code to work. The electronics is simple enough. I used a 8 port relay module and a WEMOS D1 MINI.

Connection:
Notice the relays green jumper! Remove it. The JD-VCC PIN is 12 Volt to pull relay in. Check this pin with the module you have.
Wemos D1 miniRelay Module
GNDGND
VCC 5 Volt from WemosVCC
D1Pin1
D2Pin 2
D3Pin 3
D4Pin 4
D5Pin 5
D6Pin 6
D7Pin 7
D8Pin 8
A0 not used yet. Want to use it to monitor battery power. 

Short Explain
The WEMOS have 9 digital pins. D0 to D 8 used to  switching relays on and off.

AP is use to setup the WEMOS to go on your home WIFI network.
 Client mode login to your network and you can operate switched anywhere where you have wifi access to you network. 

 Short code explaining
Step 1
The code start by checking if there are default settings in EEPROM. Like new esp8622 dont come all setup so we do it automatically in code. 
 - Yours will need it. Also if you make use of old esp. Please clean out EEPPROM first. So now code will write defaults in the EEPROM. 

Step 2
ESP will restart automatically and start up again in access point mode. 
- Now you can search for a access point WIFIcreations. Select it and Connect. Use password 0987654321. 
- Open browser. Type in address bar 192.168.4.1 this is the ESP8622 access point hard coded IP! 
- You should see this. But it can change anytime as i do updates. 

- This is the access point setup page. Like you can see. No need to explain much. 
- In the drop down list, select you access point. Put you password in password field. Password 8 char long and no longer than 20 char. Click save. If its successful it will say so under the save button. 
- Change page name of the page on top. No more than 20 char. Now you can Click restart on the top. 
 - After restart and WEMOS will connect to the your WIFI. If it all goes well. 

Step 3

To get IP for the ESP on your network. 
- To get WIFI IP for ESP8266. Check in your router for the IP address. Open browser, add IP in address bar and it should open the page. 
 - If your phone is setup as hotspot to connect ESP8266 to. Check under hotspot on phones Hotspot Connected devices. IP will show there. 
- You should see something like this. 


- Click button and it will switch on something. 
YOU DONE

 Error wrong AP or password 
 - If ESP8266 cant connect to your AP or hotspot, it will restart automatically to AP again. Else.... 
- To go back to AP mode Switch your router OFF. Restart the ESP8266 and wait 10 seconds for ESP8266 to automatically restart to AP mode. Go into AP mode set up AP and click restart button. Before that switch your Router ON again. 
 - Else clear the EEPROM
 - Default EEPROM setting is at end of the code. Change it there to yours. Clear EEPROM and it should write your default in EEPROM. 

Upload code 
Simple and easy project.
Don't upload code if relay module is connected.

The Version 1.4

The Code:

/*
   This code is for WEMOS D1 ESP8266 version 2.0

   - The code start by checking if settings is in EEPROM
   - If not it will write defaults in. Then connect to the Access Point to setup for your WIFI
   - If you do not see the AP name WIFIcreations. Restart WEMOS
   - In browser address bar type 194.168.4.1 this is AP IP
   - After setup WiFi and password click save!! Click restart and WEMOS will connect to the your WIFI
   - WIFI IP check in router for the IP. Open browser, add IP and it should open the page
   - Click button and it will switch on something

   - To go back to AP mode Switch your router OFF. restart WEMOS wait 10 seconds. Go into AP mode. Router ON
   - Else clear the EEPROM

   - default EEPROM is at end of the code.
*/

#include <ESP8266WiFi.h>
#include <EEPROM.h>


#define PAYLOAD_SIZE 7  // Number of switches to turn on
int nodePayload [PAYLOAD_SIZE];
// Name your switches here
String btnNames[] = {"Light 1", "Light 2", "Light 3", "Light 4", "Relay 1", "Relay 2"
                     , "Relay 3", "Relay 4", "Relay 5", "Relay 6"
                    };

// Pin Definitions
int  btnPins[] = {D0, D2, D3, D4, D5, D6, D7, D8 };

// WiFi Definitions for clientmode. Leave as is.
// SEE END OF CODE TO CHANGE THIS VALUES
String ssid = "";
String pass = "";

// ***** ACCESS POINT NAME AND PASSWORD ***** AP definitions
// SEE END OF CODE TO CHANGE THIS VALUES
#define AP_SSID "ADJ Creations"     // YOUR SSID FOR AP
String AP_PASSWORD = "0987654321";  // YOUR PASSWORD FOR AP
String nameConfig = "";             // PAGE NAME THAT WILL SHOW ON PAGE.

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);
IPAddress myIP = WiFi.softAPIP();

// Definitions
long lastDebounceTime = 0;  // Use to switch led on only
long debounceDelay = 1000;  // Normal operations

int wifi_AP = 0;            // pick between AP(for setup shit) or WIFI client
bool DEBUG = 1;             // 0 for no Serial output
int checkAP = 0;            // Check if AP mode is enabled. Because of error connection
int defaultsRead = 0;       // is there default values in EEPROM
//****************************************************************************//
// SETUP
//****************************************************************************//
void setup() {
  Serial.begin(9600);
  if (DEBUG) Serial.println("\n");
  initHardware();   // Setup pins and serial port
  initConfig();     // Setup page strings
  delay(5000);

  // Check(defaultsRead) if its new ESP with no Default Values else add Values
  // Check if client mode is setup, else restart and go to call AP(checkAP) mode
  Serial.print("Default is set as: ");  Serial.println(defaultsRead);
  Serial.print("AP or WIFI Mode is set as: ");  Serial.println(checkAP);
  if (checkAP && defaultsRead) {
    if (DEBUG) Serial.println("CLIENT MODE");
    setupWiFi();    // Enable for server
    wifi_AP = 1;
  }
  else { // Error conecting to client mode so go to AP mode.
    if (DEBUG) Serial.println("STARTING ACCESS POINT MODE");
    setupAP();      // Enable for AP
    wifi_AP = 0;
    if (!checkAP) {
      EEPROM.begin(512);
       EEPROM.write(203, 1); // Write default values to EEPROM
      EEPROM.end();
    }
  }
}
//****************************************************************************//
// SETUP YOUR HARDWARE HERE. PINS, MODULES ECT
//****************************************************************************//
void initHardware() {
  //ESP01=GPIO0-GPIO15 can be INPUT, OUTPUT, INPUT_PULLUP, and INPUT_PULLDOWN.
  //maximum output current is 12mA(R=V/I so 3.3V at 12mA = 275Ω min)
  Serial.begin(115200);
  delay(1000);
  for (int x = 0; x < PAYLOAD_SIZE; x++) {
    pinMode(btnPins[x], OUTPUT);
    delay(50);
    digitalWrite(btnPins[x], HIGH);
    delay(50);
  }
  if (DEBUG) Serial.println("Hardware setup done.");
  delay(200);
}
//****************************************************************************//
// CONFIGARATION PART. SET EEPROM AND GET EEPROM
//****************************************************************************//
void initConfig() {
  if (DEBUG) Serial.println("Reading EEPROM");
  EEPROM.begin(512);
  defaultsRead = EEPROM.read(201);    // Check if there are any default values written in EEPROM
  checkAP = EEPROM.read(203);   // if 0 then wifi mode not connecting to setting given
  EEPROM.end();

// If you restrat AP with no changes. It will fall back to AP  mode
  if (!defaultsRead || defaultsRead > 1) { // If higher than 1 its old eeprom data
    // If save successfull in CallAP function, disable this AP mode and restart
    if (DEBUG) Serial.println("*** SET DEFAULT VALUES TO EEPROM ***");
    defaultValues();  // Set values
    // THERE WAS NO DEFAULT VALUES IN EEPROM.
    // ESP MUST BE FORCED TO RESTART ELSE YOU WILL GET ERRORS
    EEPROM.begin(512);
    EEPROM.write(201, 1); // To get it back into Access point mode
    EEPROM.end();
    Serial.print("DEFAULTS SET. WILL RESTART NOW....");
    delay(4000);
    ESP.restart();
  }
  else {  // If defaults is set. Read it for use as new settings
    ssid = getEEPROMString(0, 20);         // SSID name of Client mode
    pass = getEEPROMString(20, 20);        // Password for Client mode
    AP_PASSWORD = getEEPROMString(40, 20); // Access Point Password
    nameConfig = getEEPROMString(60, 20);  // Top Page Name
    if (DEBUG) Serial.println(ssid);
    if (DEBUG) Serial.println(pass);
    if (DEBUG) Serial.println(AP_PASSWORD);
    if (DEBUG) Serial.println(nameConfig);
  }
  delay(200);
}
//****************************************************************************//
// THE MAIN LOOP
//****************************************************************************//
void loop() {
  if (wifi_AP) {
    CallSTA();
  }
  else {
    CallAP();
  }
}
//****************************************************************************//
// CLIENT MODE HTML
//****************************************************************************//
void CallSTA() {
  int x = 0;
  String switchPostion;
  String btnNu;
  int len;
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }

  // Wait until the client sends some data
  while (!client.available()) {
    x++;                    // Time out
    if (x == 3000) return;
    delay(1);
  }
  if (DEBUG) Serial.println("\nStation Mode Connected");
  // Read the first line of the request
  String req = client.readStringUntil('\r');
  client.flush();

  Serial.println(req);

  if (req.length() > 15) {//error corection
    //strip away received string
    req = req.substring(req.indexOf("/") + 1, req.indexOf(" HTTP/1.1"));
    if (DEBUG) Serial.println(req);

    switchPostion = req.substring( 0, 1);// Get button N for ON/F for OFF
    if (DEBUG) Serial.println(switchPostion);
    if (switchPostion == "N" || switchPostion == "F") {
      len = req.length();
      if (DEBUG) Serial.println(len);
      btnNu = req.substring(1, len);  //  Get button number pressed
      if (DEBUG) Serial.println(btnNu);
      //change the N/F to 1/0.
      //Then write a 0 or 1 to the position in the array
      if (switchPostion == "N")   nodePayload[btnNu.toInt()] = 1;
      else nodePayload[btnNu.toInt()] = 0;
    } else {
      if (DEBUG) Serial.println("Input error");
    }
    for (int x = 0; x < PAYLOAD_SIZE; x++) {
      digitalWrite(btnPins[x], nodePayload[x]);
      if (DEBUG) {
        Serial.print("Switch: ");
        Serial.print(btnPins[x]);
        Serial.print(" is ");
        Serial.print(nodePayload[x]);
        Serial.println("\n****************************");
      }
    }
  }
  client.flush();

  // Prepare the response. Start with the common header:
  String s = "HTTP/1.1 200 OK\r\n";
  s += "Content-Type: text/html\r\n\r\n";
  s += "<!DOCTYPE HTML>\r\n<html><head>";
  s += "<meta name=\"viewport\" content=\"width=devide-width, initial-scale=1\">";

  // Color in the page and buttons
  s += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}";
  s += "body { background-color: #000;}";
  s += "th, td{ text-align: center; border: 1px solid #000099;}";
  s += "p { color: red; font-size: 3; }";
  s += "H1 { font-size: 40px;}";
  s += "H5 { color: white; font-size: 10px;}";
  s += ".button { background-color: #00aa00; color: #ffffff; font-size: 25px; font-weight: bolder; text-shadow: 5px 5px 8px #000000;";
  s += "padding: 10px 30px 10px 30px; border-radius: 1px 20px 1px 20px; ; box-shadow: 4px 5px 0px #000000;";
  s += "border 0px solid #000;}";
  s += ".button2 { background-color: #aa0000; color: #ffffff; font-size: 25px; font-weight: bolder; text-shadow: 5px 5px 8px #000000;";
  s += "padding: 10px 30px 10px 30px; border-radius: 20px 1px 20px 1px; ; box-shadow: 4px 5px 0px #000000;";
  s += "border 0px solid #000;}";
  s += ".button3 { background-color: #dddddd; color: #0000aa; font-size: 30px; font-weight: bolder; text-shadow: 5px 5px 8px #000000;";
  s += "padding: 15px 10px 15px 10px; border-radius: 20px 20px 20px 20px; ; box-shadow: 5px 5px 10px #cc0000;";
  s += "}</style>";
  s += "<title>Wifi Creations</title></head>";
  s += "<body bgcolor=#777><center>";
  s += "<table style=\"width: 100%;border: 1px solid #000099;\"><tr><td>";
  s += "<h1><center><button class=\"button3\">&#127744;&emsp;";  s += nameConfig;  s += "</button></center></h1>";

  s += "</td></tr><tr><td>";
  //create buttons on page
  for (int z = 0; z <= PAYLOAD_SIZE; z++) {
    delay(2);
    if (nodePayload[z] == 1) {
      s += "<p>&emsp;&emsp;<A HREF='/F";
      s += String(z);
      s += "'><button class=\"button\">";
      s += btnNames[z];
      s += "</button></A>&emsp;</p>";
    }
    else if (nodePayload[z] == 0) {
      s += "<p>&emsp;<A HREF='/N";
      s += String(z);
      s += "'><button class=\"button2\">";
      s += btnNames[z];
      s += "</button></A>&emsp;</p>";
    }
  }

  int emoji = random(8986, 129510);
  s += "</center></td></tr></table><br /><br /><br />";
  s += "<a href=http://github.com/ADJ7WTB/ESP8622_setup_manager><h5>&#127798;&emsp;Code for this project</h5></a>";
  s += "<a href=http://adjwtb.blogspot.com><h5>&#128149;&emsp;Other project with WEMOS</h5></a>";
  s += "<a href=https://www.w3schools.com/charsets/ref_emoji.asp><h5>&#";
  s += emoji;
  s += ";&emsp;School HTML & Emoji's</h5></a>";
  s += "</center></body></html>";

  // Send the response to the client
  client.print(s);
  delay(20);
  if (DEBUG) Serial.println("*** Client disonnected ***");

  // The client will actually be disconnected
  // when the function returns and 'client' object is detroyed
}
//****************************************************************************//
// ACCESS POINT MODE HTML
// AP only used to setup CLIENT MODE - SSID and PASSWORD and PAGE NAME
//****************************************************************************//
void CallAP() {
  int x = 0;
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  initConfig(); // Read configs before changes
  // Wait until the client sends some data
  while (!client.available()) {
    x++;
    if (x == 5000) return;
    delay(1);   ///hang
  }
  if (DEBUG) Serial.println("\nAccess Point Connected");
  // Read the first line of the request
  String req = client.readStringUntil('\r'); // Read req received
  client.flush();

  // Some EEPROM checks to see if you did save
  bool saveEEPROM = false;
  bool saveAPEEPROM = false;
  bool configEEPROM = false;

  if (req.substring(0, 13) == "GET /msg?ssid") {
    saveEEPROM = prossessForm(req);   //proccess data received. save it to the EEPROM
  }  //save AP password
  else if (req.substring(0, 15) == "GET /msg?APpass") {
    saveAPEEPROM = prossessForm(req); //proccess data received. save it to the EEPROM
  }  //config names
  else if  (req.substring(0, 12) == "GET /default") {
    configEEPROM = prossessForm(req); //proccess data received. save it to the EEPROM
  }
  else if  (req.substring(0, 12) == "GET /RESTART") {
    if (DEBUG) Serial.println("Restart to AP mode in 10 seconds.............");
    delay(10000);  // Restart button clicked
    ESP.restart();
  }

  delay(10);
  initConfig(); //get the new values

  client.flush();

  // Prepare the response. Start with the common header:
  String s = "HTTP/1.1 200 OK\r\n";
  s += "Content-Type: text/html\r\n\r\n";
  s += "<!DOCTYPE HTML>\r\n<html><head>";
  s += "<meta name=\"viewport\" content=\"width=devide-width, initial-scale=1\">";
  // Color in the page and buttons
  s += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}";
  s += "body { background-color: #ab631d;}";
  s += "th, td{ text-align: center; border: 1px solid #000099;}";
  s += "p { color: black; font-size: 10; }";
  s += "H1 { font-size: 40px;}";
  s += "H5 { color: white; font-size: 20px;}";
  s += ".button { background-color: #00aa00; color: #ffffff; font-size: 15px; font-weight: bolder; text-shadow: 5px 5px 8px #000000;";
  s += "padding: 5px 5px 5px 5px; border-radius: 1px 20px 1px 20px; box-shadow: 4px 5px 0px #000000;";
  s += "border 0px solid #000;}";
  s += ".button3 { background-color: #dddddd; color: #0000aa; font-size: 30px; font-weight: bolder; text-shadow: 5px 5px 8px #000000;";
  s += "padding: 15px 10px 15px 10px; border-radius: 20px 20px 20px 20px; ; box-shadow: 5px 5px 10px #cc0000;";
  s += "}</style>";
  s += "<title>SERVER</title></head><body>";
  // Starting page tables
  s += "<table style=\"width: 100%;border: 1px solid #000099;\"><tr><th>";
  s += "<h1><center><button class=\"button3\">&#127744;&emsp;";  s += nameConfig;  s += "</button></center></h1>";

  s += "</th></tr></table><table style=\"width: 100%;border: 1px solid #000099;\"><tr><td>";
  // Button to restart AP
  s += "<p>Restart after setting up your WIFI details. It will auto-connect if your WIFI password is correct.</p><br />";
  s += "<center><a href=RESTART><button class=\"button\">RESTART</button></a></center><br>";
  //scan for hotspots
  //************************
  s += "</td></tr><tr><td>";
  int n = WiFi.scanNetworks();
  delay(10);
  if (n == 0)  {
    if (DEBUG) Serial.println("Scan found no WIFI hotspot.");
    s += "<b>NO WIFI-HOTSPOT FOUND, REFRESH PAGE AGAIN.</b>";
  }
  else  {
    if (DEBUG) Serial.println("Scan found WIFI hotspot.");
    s += "<form action='msg'><b>WIFI NETWORKS FOUND</b><br><select name='ssid' width='40'> ";
    for (int i = 0; i < n; i++)
    {
      // Print SSID and RSSI for each network found
      if (n == 0) {
        s += "<option selected name='ssid' value'";
      }
      else {
        s += "<option name='ssid' value'";
      }
      if (DEBUG) Serial.print(i);
      if (DEBUG) Serial.print("\t");
      if (DEBUG) Serial.println(WiFi.SSID(i));
      s += WiFi.SSID(i);
      s += "'>";
      s += WiFi.SSID(i);
      s += "</option>";
      delay(2);
    }
    s += "</select>";
    s += "<p>Password rules. No special char!! No More than 20 char. no less than 8 char</p>";
    s += "<p><b>Password No special char!!</b><br><input type='password' name='pass' size=20 ><br><input type='submit' value='SAVE'></form>";
    if (saveEEPROM) s += "<p>SSID and Password saved to EEPROM.";
    else s += "<p>SSID and Password not saved to EEPROM. SSID should be 2 or more char. Password should be 10 and more ";
  }
  s += "</td></tr><tr><td>";
  //******* AP save password
  s += "<form action='msg'><b>Change Access Point Password.</b><br><br>If you dont want the default password.";
  s += "<input type='password' name='APpass' size=20 ><br>Repeat new password<br>";
  s += "<input type='password' name='repeatpass' size=20 >";
  s += "<br><input type='submit' value='SAVE AP'></form>";
  if (saveAPEEPROM) s += "<p>AP Password saved to EEPROM.";
  else s += "<p>AP Password not saved to EEPROM. Password need to be more than 8 char or must be the same. Dont use special char like =&?%";

  s += " </td></tr><tr><td>";
  s += "<form action='default'><b>Change Page Name. No spaces, and less than 20 char.</b>";
  s += "<br><input type='text' name='page' size=20 ><br>";
  s += "<input type='submit' value='SAVE'></form>";
  s += " </td></tr></table>";
  int emoji = random(8986, 129510);
  s += "</center></td></tr></table><br /><br /><br />";
  s += "<a href=http://github.com/ADJ7WTB/ESP8622_setup_manager><h5>&#127798;&emsp;Code for this project</h5></a>";
  s += "<a href=http://adjwtb.blogspot.com><h5>&#128149;&emsp;Other project with WEMOS</h5></a>";
  s += "<a href=https://www.w3schools.com/charsets/ref_emoji.asp><h5>&#";
  s += emoji;
  s += ";&emsp;School HTML & Emoji's</h5></a>";
  s += "</body></html>";

  // Send the response to the client
  client.print(s);
  delay(1);
  if (DEBUG) Serial.println("Client disconnected\n");
}
//****************************************************************************//
// DATA PROSSESS - DATA RECEIVED FROM AP IS STRIPPED INTO PARTS
// THEN SAVED TO EEPROM AS NEW DEFAULTS
//****************************************************************************//
bool prossessForm(String sReceived) {
  String str1 = "";
  String str2 = "";
  String str3 = "";
  String str4 = "";
  String temp = "";
  //Example: GET /msg?APpass=12345678&repeatpass=1234567 HTTP/1.1
  //Example: GET /msg?ssid=SSIDname&pass=PASSWORD HTTP/1.1
  //Example: GET /buttonNames?onname=ON&offname=OFF HTTP/1.1
  if (DEBUG) {
    Serial.println("*** START OF DATA PROCESSING ***");
    Serial.print("RECEIVED STRING: ");
    Serial.println(sReceived);
  }
  sReceived.replace("%25", "%");
  sReceived.replace("%40", "@");
  sReceived.replace("%23", "#");
  sReceived.replace("%26", "&");
  sReceived.replace("%2F", "/");
  sReceived.replace("%24", "$");
  sReceived.replace("%21", "!");
  sReceived.replace("%3F", "?");
  sReceived.replace("%D3", "=");
  sReceived.replace("%2B", "+");
  sReceived.replace("%28", "(");
  sReceived.replace("%29", ")");
  sReceived.replace("%27", "'");
  sReceived.replace("%3A", ":");
  sReceived.replace("%22", "\"");
  sReceived.replace("%2C", ",");
  sReceived.replace("%29", ")");
  sReceived.replace("%5B", "[");
  sReceived.replace("%5D", "]");
  sReceived.replace("%7B", "{");
  sReceived.replace("%7D", "}");
  sReceived.replace("%3C", "<");
  sReceived.replace("%3E", ">");
  sReceived.replace("%5E", "^");
  sReceived.replace("%7E", "~");
  int len = sReceived.length(); // You need the length of the incoming string
  if (DEBUG) {
    Serial.print("RECEIVED LENGTH: ");
    Serial.println(len);
    Serial.print("FILTER RECEIVED STRING: ");
    Serial.println(sReceived);
  }

  // RECEIVED -- GET /msg?APpass=12345678&repeatpass=1234567 HTTP/1.1
  // Get string between -- GET /msg? and HTTP/1.1
  temp = sReceived.substring(sReceived.indexOf("?") + 1, sReceived.indexOf(" HTTP/1.1"));
  // temp value = APpass=12345678&repeatpass=1234567
  if (DEBUG) {
    Serial.print("Temp string: ");
    Serial.println(temp);
    Serial.println("***********************************");
  }
  str1 = temp.substring(0, temp.indexOf("="));// Get string between -- 0 and =
  //str1 = APpass
  len = temp.length();// temp 33 = APpass=12345678&repeatpass=1234567
  temp = temp.substring(temp.indexOf("=") + 1, len);// Get string between -- GET /msg? and HTTP/1.1
  // temp value = 12345678&repeatpass=1234567
  str2 = temp.substring(0, temp.indexOf("&"));// Get string between -- 0 and &
  //str2 = 12345678
  len = temp.length();// temp 27 = 12345678&repeatpass=1234567
  temp = temp.substring(temp.indexOf("&") + 1, len);// Get string between -- & and toEnd
  // temp value = repeatpass=1234567
  str3 = temp.substring(0, temp.indexOf("="));// Get string between -- 0 and =
  len = temp.length();// temp 17 = repeatpass=1234567
  temp = temp.substring(temp.indexOf("=") + 1, len);// Get string between -- = and end
  // temp value = 1234567
  str4 = temp;

  if (DEBUG) {
    Serial.println("PROSSESSED DATA ");
    Serial.println("1: " + str1);  //HEADING (SSID or APPASS or PAGE NAME)
    Serial.println("2: " + str2);  //DATA(ssidName or apPassword)
    Serial.println("3: " + str3);  //HEADING(wifiPass or AP repeatpass)
    Serial.println("4: " + str4);  //DATA(wifiPASS or APpass)
    Serial.println("***********************************");
  }
  //Example: GET /msg?APpass=12345678&repeatpass=1234567 HTTP/1.1
  //Example: GET /msg?ssid=SSIDname&pass=PASSWORD HTTP/1.1
  if (str1 == "APpass" || str1 == "ssid") {
    int len1 = str2.length();
    int len2 = str4.length();
    if (len1 < 3 || len2 < 7) {
      if (DEBUG) {
        Serial.println("Length to short to save to EEPROM");
        Serial.print("SSID length: ");
        Serial.println(len1);
        Serial.print("PASSWORD length: ");
        Serial.println(len2);
        Serial.println("***********************************");
      }
      return false;
    }
    if (str2.indexOf(" ") >= 0) return false;
  }
  //  if (str2.indexOf("%") >= 0) return false;
  //  if (str4.indexOf("%") >= 0) return false;
  //  if (DEBUG) Serial.println("UNKNOWN SPECIAL CHAR USED AS PASSWORD.");
  if (str1 == "ssid") {
    if (DEBUG) Serial.println("SSID Save to EEPROM");
    //Function to save to EEPROM
    setEEPROMString(0, 20, str2);  //start at address 0 for SSID
    setEEPROMString(20, 20, str4); //start at address 20 for password
    return true;
  }
  else if (str1 == "APpass") {
    if (str2 == str4) {
      if (DEBUG) Serial.println("AP password saved.");
      //Function to save to EEPROM
      setEEPROMString(40, 20, str2); //start at address 20 for password
      return true;
    }
    else {
      if (DEBUG) Serial.println("AP password entered is not the same.");
      return false;
    }
  }
  else if (str1 == "page") {
    if (str2 == "") return false;
    if (DEBUG) Serial.println("Page Name Save to EEPROM");
    //Function to save to EEPROM
    setEEPROMString(60, 20, str2);
    return true;
  }
  if (DEBUG) Serial.println("*** END OF DATA PROCESSING ***");
}
//****************************************************************************//
// START AND SETUP CLIENT MADE
//****************************************************************************//
void setupWiFi() {
  //starting WIFI
  WiFi.mode(WIFI_STA);   //station modes enable
  WiFi.disconnect();
  delay(100);
  // Connect to WiFi network
  if (DEBUG) Serial.println("\nWaiting Connect to " + ssid);
  WiFi.begin(ssid.c_str(), pass.c_str());

  int xx = 0;
  while (WiFi.status() != WL_CONNECTED) {
    xx++;
    if (DEBUG) Serial.println(xx);
    delay(150);
    //LED_BUILTIN DISABLE. ITS USED FOR D4
    //digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    if (xx > 100) { //time out. go back to AP mode
      xx = 0;
      EEPROM.begin(512);
      EEPROM.write(203, 0);// 0 Set AP active in EEPROM
      EEPROM.end();
      if (DEBUG) Serial.println("ERROR TIME OUT. RESTARTING TO AP NOW.....");
      ESP.restart();
    }
  }
  if (DEBUG) Serial.println("");
  if (DEBUG) Serial.println("WiFi connected");

  // Start the server
  server.begin();
  if (DEBUG) Serial.println("Server started");

  // Print the IP address
  if (DEBUG) Serial.println(WiFi.localIP());
}
//****************************************************************************//
// START AND SETUP ACCESS POINT MODE
//****************************************************************************//
void setupAP() {
  WiFi.mode(WIFI_AP);   //AP modes enable
  if (DEBUG) Serial.println("\nStarting Access Point...");
  /* You can remove the password parameter if you want the AP to be open. */
  WiFi.softAP(AP_SSID, AP_PASSWORD.c_str());
  if (DEBUG) {
    Serial.println("HTTP server started");
    Serial.print("AP IP address: ");
    Serial.println(myIP);
    Serial.print("*****************************************\n");
    WiFi.printDiag(Serial);
    Serial.print("*****************************************\n");
  }
  server.begin();
}
//****************************************************************************//
// SET AND GET EEPROM
//****************************************************************************//
int eepromStart = 0;  //Location where to start saving to EEPROM
String getEEPROMString(int start, int len) {
  EEPROM.begin(512);  delay(10);  String string = "";
  for (int i = eepromStart + start; i < eepromStart + start + len; i++) {
    string += char(EEPROM.read(i));
    delay(2);
  }
  string = string.substring(0, string.indexOf(" "));
  string.replace("+", " ");
  EEPROM.end();
  return string;
}

void setEEPROMString(int start, int len, String string) {
  EEPROM.begin(512);
  delay(10);
  int si = 0;
  for (int i = eepromStart + start; i < eepromStart + start + len; i++) {
    char c;
    if (si < string.length()) {
      c = string[si];
    } else {
      c = 0;
    }
    Serial.print(i);
    Serial.println(c);
    EEPROM.write(i, c);
    delay(2);
    si++;
  }
  EEPROM.end();
}
//****************************************************************************//
// SET DEFAULT VALUES TO EEPROM
// NEW ESP HAVE NO SETTINGS, AP WILL NOT SHOW IF NO SSID IS SET IN EEPROM
//****************************************************************************//
void defaultValues() { // 20 CHAR IS USED. BUT YOU CAN MAKE IT MORE
  setEEPROMString(0, 20, "AndreWiFi");     //String ssid;
  setEEPROMString(20, 20, "Andre1234");   //String pass;
  setEEPROMString(40, 20, "0987654321"); //String AP_PASSWORD;
  setEEPROMString(60, 20, "ADJ Creations");  //String nameConfig;
}

Thursday, December 4, 2014

Stair or Path Way Lights

Intro:

Did you ever wish you had light that comes on as you walk up the stairs? With small kids running up and down stairs in the dark can be dangerous. I created lights that will come on as you go up or down the stairs. It use PIR sensors to see you. So lets see what you will need.
This is not a tutorial in how Arduino works or electronics. You must know at least how Arduino works to do this project. Most code is from Arduino IDE examples. I just put it all together to make it work.

Buy list:

  1. 1 x Arduino Uno
  2. 2 x DSN-FIR800 PIR sensors or compatible ones
  3. 14 x WS2801 30mm LEDS 
  4. 1 x 12 Volt 2 Amp Switch Mode power supply
  5. 6 x 22k Ohm Resistors
  6. 1 x 15k Ohm Pot
  7. Dip 5 Switch or Dip 2 & 3 Switch

Arduino Uno:



The Arduino Uno comes with 15 digital pins and 6 analog pins. The analog pins will be used as digital pin 15, 16, 17, 18 and 19. Analog A0 will stay as it is but its digital pin is 14.

 DSN-FIR800 PIR:


This PIR sensor comes with 3 pins. 2 Setting pots for Time(Tx) on and Sensitivity(Sx). The signal out can be changed to LOW but we need it HIGH so we leave it as is. First sensor pin 2 will be connected to Arduino pin 5 and the other sensor pin 2 to the Aruino pin 3. PIR pin 1 goes to 5 volt on Arduino and Ground to Ground on Arduino.
  • Pin 1 is 5 Volt
  • Pin 2 is Signal out is HIGH 
  • Pin 3 is Ground

WS2801 30mm LEDS:



This is where the magic starts. This LED's have 3 RGB LED's inside. They are fitted with a WS2801 chip that control the color and address which one should be on. There are 4 wires Connected to them.
  1. First wire is 12 volt only!
  2. Then the clock wire that goes to Arduino Pin12.
  3. Then the data wire that goes to Arduino Pin13.
  4. Then Ground. Important Ground must be connected to Arduino Ground also.
  5. Very important! Look at the arrow on the LED to see direction of the DATA flow. 

Fritzing:

Fritzing is a circuit building program that helps a lot with explaining and layout of components.
This image is to show you where to put the LED wire and the 2 PIR sensor wires.


All resistors are 22k ohm resistors. They are use to pull the Arduino INPUT pins HIGH. So when you press or select the buttons they will pull Arduino pins LOW. The code will do the rest.
  • D2 is a push button to change to next demo.
  • A1 will switch on Demo mode.
  • A2 is to set the speed of the next lights to turn on.
  • A3 to set Blue value.
  • A4 to set Green value.
  • A5 to set Red value.
The pot is connected between 5 Volt and Ground. the wiper goes to pin A0 on Arduino.


MY CODE: 

#include "WS2801.h"  //for use with WS2801 Chip
#include "SPI.h"
#include <EEPROM.h>  //to write and read from EEPROM

// BE SURE TO CHECK YOUR PIXELS TO SEE WHICH WIRES TO USE!
uint8_t dataPin  = 13;
uint8_t clockPin = 12;
// Connect the ground wire Pixels to Arduino ground
// Set the first variable to the NUMBER of pixels. 5 = 5 pixels in a row
WS2801 strip = WS2801(15, dataPin, clockPin);
// EEPROM addresses to save to
const int addr = 0;  
const int addrR = 1;
const int addrG = 2;
const int addrB = 3;
const int addrSpeed = 4;
// Where we going to store to byte
byte value;  
// Temp holds your color value
int color;
// Motion sensor inputs
const int bottomPIR = 3;
const int topPIR = 5;
// Analog pin used as digital pins 14 to 19
const int redSwitch = 15; //Red Switch
const int greenSwitch = 16; //Green Switch
const int blueSwitch = 17; //Blue Switch
const int speedSwitch = 18; //Speed switch
const int demoSwitch = 19; //Demo Switch
// Which demo to run :) EEPROM save this value
unsigned int switchSelect;  
// The time lights stays on before all goes dark
unsigned int lighton = 5000;
// Time lights comes on one by one
unsigned int lightspeed = 100; 
// LED Colors
unsigned int RGB1 = 90;
unsigned int RGB2 = 125;
unsigned int RGB3 = 125;
//************************************************************
void setup() {
  Serial.begin(19200);
  while (!Serial) {
    delay(10);
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  pinMode(topPIR, INPUT);
  pinMode(bottomPIR, INPUT);
  
  pinMode(redSwitch, INPUT);
  pinMode(greenSwitch, INPUT);
  pinMode(blueSwitch, INPUT);
  pinMode(speedSwitch, INPUT);
  pinMode(demoSwitch, INPUT);
  
  delay(400);//Wait for serial LCD to start up
  Serial.print("Reading EEPROM   ");
  Serial.print('\n');
  delay(300);

  strip.begin();// Start WS2801
  strip.show();// Start al off
  // Read addresses in the EEPROM then save it
  value = EEPROM.read(addr); 
  switchSelect = int(value);
  RGB1 = EEPROM.read(addrR);
  RGB2 = EEPROM.read(addrG);
  RGB3 = EEPROM.read(addrB);
  // Read this addresses in the EEPROM then save it
  //Miltiply by 10 to allow more time for lights
  lightspeed = EEPROM.read(addrSpeed);  
  lightspeed =  lightspeed * 10;
  // Set interrupt button. Help select the demo
  attachInterrupt(0, debounceInterrupt, HIGH); 
  Serial.print("Starting....      ");
  Serial.print('\n');
  delay(1000);
}
//************************************************************
// We use long variables because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;// Last time the output pin was pressed
long debounceDelay = 350;// Time to wait before button will be active
boolean change = true;// Needed to save to EEPROM
void debounceInterrupt() {
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    switchSelect++;
    lastDebounceTime = millis();
    change = true;
  }
}
//************************************************************
int Direction = 0;// What direction we moving
void loop() {
  //***  Settings  ***
  if (!digitalRead(redSwitch)) {//A1 to A5 used as digital pins for switches to set values
    while (!digitalRead(redSwitch)) {// Stay active till value is set
      change = true;//Update the colors
      pickColor();// Function to select a color
      Serial.print("Red: ");// Show me the color value on LCD
      Serial.print(color);
      Serial.print("        ");
      Serial.print('\n');
      WipeDown(Color(color, RGB2, RGB3), 1);// Show me the color
    }
    EEPROM.write(addrR, color);// Save value to EEPRM
  }  else if (!digitalRead(greenSwitch)) {
    while (!digitalRead(greenSwitch)) {
      change = true;
      pickColor();
      Serial.print("Green: ");
      Serial.print(color);
      Serial.print("      ");
      Serial.print('\n');
      WipeDown(Color(RGB1, color, RGB3), 1);
    }
    EEPROM.write(addrG, color);
  }  else if (!digitalRead(blueSwitch)) {
    while (!digitalRead(blueSwitch)) {
      change = true;
      pickColor();
      Serial.print("Blue: ");
      Serial.print(color);
      Serial.print("       ");
      Serial.print('\n');
      WipeDown(Color(RGB1, RGB2, color), 1);
    }
    EEPROM.write(addrB, color);
  }  else if (!digitalRead(speedSwitch)) {
    // You can only save to EEPROM 100 000 times. Save it this way
    change = true;// When you done picking speed save to EEPROM
    while (!digitalRead(speedSwitch)) {
      double T;// Needed to test only
      lightspeed = analogRead(A0);// Read analog pin
      lightspeed = map(lightspeed, 0, 1023, 0, 255);// Map it to workable value
      // DONT use Constrains it comes with errors
      if (lightspeed > 255) {// Constrains it between 0 and 255
        lightspeed = 255;
      }  else if (lightspeed <= 1) {
        lightspeed = 0;
      }
      T =  lightspeed * 10;// Convert to usable value
      Serial.print("Speed: ");
      Serial.print(T);
      Serial.print("      ");
      Serial.print('\n');   
      for (int i = strip.numPixels() ; i >= 0; i--) {
        strip.setPixelColor(i, Color(175, 70, 0));
      }
      strip.show();
      delay(T);
      AllOff();
      delay(T);
    }
    EEPROM.write(addrSpeed, lightspeed);// Save to EEPROM
  }
  if (change) {// IF true 
    change = false;// Set False
    EEPROM.write(addr, switchSelect);// Save to EEPROM
    value = EEPROM.read(addr); 
    switchSelect = int(value);
    RGB1 = EEPROM.read(addrR);
    RGB2 = EEPROM.read(addrG);
    RGB3 = EEPROM.read(addrB);
  }
    //if DEMO is selected run it
  if (digitalRead(demoSwitch)) {//NO DEMO
    //check if PIR detect motion
    if (digitalRead(topPIR) == HIGH) {
        Serial.println("PIR 1 Active     ");
        Serial.println('\n');
        WipeUp(Color(RGB1, RGB2, RGB3), lightspeed);// Lights on
        if (Direction == 0) Direction = 1;// To switch off in same direction
      }
    else if (digitalRead(bottomPIR) == HIGH) {
        Serial.println("PIR 2 Active      ");
        Serial.println('\n');
        WipeDown(Color(RGB1, RGB2, RGB3), lightspeed);
        if (Direction == 0) Direction = 2;
      }
    else {
      if (Direction == 1) {//switch lights off
        delay(lighton);
        WipeUp(Color(0, 0, 0), lightspeed);
      }
      if (Direction == 2) {
        delay(lighton);
        WipeDown(Color(0, 0, 0), lightspeed);
      }
      Direction = 0;//Reset it else it will on switch on again
    }
  }
  else if (!digitalRead(demoSwitch)) {
    demo();  // Call DEMO
  }
}
//************************************************************
// When function is called. it will display the lights
//Add funtions so its not needed to repeat this calls over and over
//it save time
void WipeUp(uint32_t c, double wait) {
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();// Activate Lights
    delay(wait);//Waiting time that is saved in EEPROM
  }
}
//************************************************************
void WipeDown(uint32_t c, double wait) {
  for (int i = strip.numPixels() ; i >= 0; i--) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}
//************************************************************
void AllOff() {
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, 0);
  }
  strip.show();
}
//************************************************************
//***** DEMO MODES *****
// Ths is just repeat of top functions. its needed for demo mode only
void demo() {
  //  Serial.println("DEMO IS RUNNING....");
  int PicR = random(255);
  int PicG = random(255);
  int PicB = random(255);
  switch (switchSelect) {
    case 1:
      Serial.print("Demo 1 Running    ");
      Serial.println('\n');
      WipeDown(Color(color, RGB2, RGB3), lightspeed);
      delay(lightspeed);
      AllOff();
      delay(lightspeed);
      break;
    case 2:
      Serial.print("Demo 2 Running    ");
      Serial.println('\n');
      strip.setPixelColor(random(strip.numPixels()), Color(random(255), random(255), random(255)));
      strip.show();
      delay(300);
      break;
    case 3:
      Serial.print("Demo 3 Running    ");
      Serial.println('\n');
      int i, j;
      for (j = 0; j < 256; j++) {   // 3 cycles of all 256 colors in the wheel
        for (i = 0; i < strip.numPixels(); i++) {
          strip.setPixelColor(i, Wheel( (i + j) % 255));
          strip.show();
        }
        // write all the pixels out
        delay(30);
      }
      break;
    case 4:
      Serial.print("Demo 4 Running    ");
      Serial.println('\n');
      strip.setPixelColor(random(strip.numPixels()), Color(random(255), random(255), random(255)));
      strip.show();
      delay(150);
      AllOff();
      delay(80);
      break;
    case 5:
      Serial.print("Demo 5 Running    ");
      Serial.println('\n');
      for (i = 0; i < strip.numPixels(); i++) {
        strip.setPixelColor(i, Color(random(255), random(255), random(255)));
        strip.show();
        delay(150);
      }
      AllOff();
      delay(150);
      break;
    case 6:
      Serial.print("Demo 6 Running    ");
      Serial.println('\n');    
      for (int i = strip.numPixels() ; i >= 0; i--) {
        strip.setPixelColor(i, Color(random(255), random(255), random(255)));
        strip.show();
        delay(100);
      }

      delay(500);
      break;
    case 7:
      Serial.print("Demo 7 Running    ");
      Serial.println('\n');
      for (int i = 0 ; i < strip.numPixels(); i++) {
        strip.setPixelColor(i, Color(PicR, PicG, PicB));
        strip.show();
        delay(180);
      }
      break;
    case 8:
      Serial.print("Demo 8 Running    ");
      Serial.println('\n');
      for (int i = strip.numPixels() ; i >= 0; i--) {
        strip.setPixelColor(i, Color(PicR, 0, PicB));
      }
      strip.show();
      delay(100);
      AllOff();
      delay(50);
      break;
      
    default:
      Serial.print("NOTHING SELECTED ");
      Serial.println('\n');
      AllOff();
      while(!change){
        if (analogRead(A5) > 100){change = 1;}
        delay(10); }        
      break;
  }
  if (switchSelect > 8) switchSelect = 0;//End of demo - start over
}
//************************************************************
//*****  Needed Functions  *****
// Create a 24 bit color value from R,G,B
uint32_t Color(byte r, byte g, byte b)
{
  uint32_t c;
  c = r;
  c <<= 8;
  c |= g;
  c <<= 8;
  c |= b;
  return c;
}

void pickColor() {
  color = analogRead(A0);//Read analog pin
  color = map(color, 0, 1023, 0, 255);//map it
  if (color > 255) {// Constrains it between 0 and 255
    color = 255;
  }
  else if (color <= 1) {
    color = 0;
  }
}
//************************************************************
//Input a value 0 to 255 to get a color value.
//The colours are a transition r - g -b - back to r
uint32_t Wheel(byte WheelPos)
{
  if (WheelPos < 85) {
    return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}